]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'jfs-3.12' of git://github.com/kleikamp/linux-shaggy
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 22 Oct 2013 08:01:11 +0000 (09:01 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 22 Oct 2013 08:01:11 +0000 (09:01 +0100)
Pull jfs bugfix from David Kleikamp:
 "Just a patch to fix an oops in an error path"

* tag 'jfs-3.12' of git://github.com/kleikamp/linux-shaggy:
  jfs: fix error path in ialloc

3108 files changed:
CREDITS
Documentation/ABI/stable/sysfs-bus-usb
Documentation/ABI/testing/sysfs-class-mtd
Documentation/ABI/testing/sysfs-devices-power
Documentation/ABI/testing/sysfs-power
Documentation/DocBook/mtdnand.tmpl
Documentation/acpi/dsdt-override.txt
Documentation/aoe/udev.txt
Documentation/arm64/tagged-pointers.txt
Documentation/block/00-INDEX
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/gpio/gpio-mcp23s08.txt
Documentation/devicetree/bindings/gpio/gpio-palmas.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-tz1090-pdc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-tz1090.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
Documentation/devicetree/bindings/gpu/samsung-g2d.txt
Documentation/devicetree/bindings/input/input-reset.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/egalax-ts.txt
Documentation/devicetree/bindings/leds/leds-lp55xx.txt
Documentation/devicetree/bindings/leds/pca963x.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/exynos-dw-mshc.txt
Documentation/devicetree/bindings/mmc/fsl-esdhc.txt
Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt [moved from Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt with 93% similarity]
Documentation/devicetree/bindings/mmc/tmio_mmc.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/net/fsl-tsec-phy.txt
Documentation/devicetree/bindings/pci/designware-pcie.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/serial/qca,ar9330-uart.txt [moved from Documentation/devicetree/bindings/tty/serial/qca,ar9330-uart.txt with 100% similarity]
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/devicetree/bindings/vendor-prefixes.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 [moved from fs/cifs/AUTHORS with 99% similarity]
Documentation/filesystems/cifs/CHANGES [moved from fs/cifs/CHANGES with 100% similarity]
Documentation/filesystems/cifs/README [moved from fs/cifs/README with 100% similarity]
Documentation/filesystems/cifs/TODO [moved from fs/cifs/TODO with 100% similarity]
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/hwmon/w83791d
Documentation/hwmon/w83792d
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/sound/alsa/HD-Audio-Models.txt
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/Kconfig
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.h
arch/arc/include/asm/spinlock_types.h
arch/arc/include/asm/uaccess.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/ptrace.c
arch/arc/kernel/setup.c
arch/arc/kernel/signal.c
arch/arc/kernel/time.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/Makefile
arch/arm/boot/Makefile
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/am335x-bone-common.dtsi [new file with mode: 0644]
arch/arm/boot/dts/am335x-bone.dts
arch/arm/boot/dts/am335x-boneblack.dts [new file with mode: 0644]
arch/arm/boot/dts/armada-370-netgear-rn102.dts
arch/arm/boot/dts/armada-xp.dtsi
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/atlas6.dtsi
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/imx27.dtsi
arch/arm/boot/dts/imx51.dtsi
arch/arm/boot/dts/imx6q-pinfunc.h
arch/arm/boot/dts/kirkwood.dtsi
arch/arm/boot/dts/omap3-beagle-xm.dts
arch/arm/boot/dts/omap3-igep.dtsi
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/omap4-panda-common.dtsi
arch/arm/boot/dts/omap4-sdp.dts
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/prima2.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/r8a73a4.dtsi
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/r8a7778.dtsi
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/r8a7790.dtsi
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/boot/install.sh
arch/arm/common/edma.c
arch/arm/common/mcpm_entry.c
arch/arm/common/sharpsl_param.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/configs/multi_v7_defconfig
arch/arm/crypto/aes-armv4.S
arch/arm/include/asm/Kbuild
arch/arm/include/asm/dma-contiguous.h
arch/arm/include/asm/jump_label.h
arch/arm/include/asm/mach/arch.h
arch/arm/include/asm/mcpm.h
arch/arm/include/asm/outercache.h
arch/arm/include/asm/syscall.h
arch/arm/include/asm/uaccess.h
arch/arm/kernel/entry-common.S
arch/arm/kernel/entry-header.S
arch/arm/kernel/head.S
arch/arm/kvm/reset.c
arch/arm/lib/Makefile
arch/arm/lib/xor-neon.c
arch/arm/mach-at91/at91rm9200_time.c
arch/arm/mach-at91/at91sam926x_time.c
arch/arm/mach-at91/at91sam9g45_reset.S
arch/arm/mach-at91/at91x40_time.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-davinci/board-dm365-evm.c
arch/arm/mach-davinci/include/mach/serial.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-fixup-mux.c
arch/arm/mach-imx/clk-imx27.c
arch/arm/mach-imx/clk-imx51-imx53.c
arch/arm/mach-imx/clk.h
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-imx/mm-imx25.c
arch/arm/mach-imx/mm-imx5.c
arch/arm/mach-imx/system.c
arch/arm/mach-integrator/pci_v3.h
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/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-mvebu/coherency.c
arch/arm/mach-mvebu/pmsu.c
arch/arm/mach-mvebu/system-controller.c
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-rx51-peripherals.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/cpuidle44xx.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/gpmc-onenand.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/mux.h
arch/arm/mach-omap2/mux34xx.c
arch/arm/mach-omap2/omap-smp.c
arch/arm/mach-omap2/omap_device.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-omap2/timer.c
arch/arm/mach-sa1100/collie.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/clock-r8a73a4.c
arch/arm/mach-shmobile/clock-sh73a0.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-u300/Kconfig
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/cache-l2x0.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/dma-mapping.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/Kconfig.debug
arch/arm64/configs/defconfig
arch/arm64/include/asm/hwcap.h
arch/arm64/include/asm/uaccess.h
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/process.c
arch/arm64/kernel/setup.c
arch/arm64/mm/fault.c
arch/arm64/mm/hugetlbpage.c
arch/arm64/mm/init.c
arch/arm64/mm/tlb.S
arch/avr32/Kconfig
arch/avr32/include/asm/Kbuild
arch/avr32/include/asm/cputime.h [deleted file]
arch/avr32/include/asm/delay.h [deleted file]
arch/avr32/include/asm/device.h [deleted file]
arch/avr32/include/asm/div64.h [deleted file]
arch/avr32/include/asm/emergency-restart.h [deleted file]
arch/avr32/include/asm/futex.h [deleted file]
arch/avr32/include/asm/irq_regs.h [deleted file]
arch/avr32/include/asm/local.h [deleted file]
arch/avr32/include/asm/local64.h [deleted file]
arch/avr32/include/asm/percpu.h [deleted file]
arch/avr32/include/asm/scatterlist.h [deleted file]
arch/avr32/include/asm/sections.h [deleted file]
arch/avr32/include/asm/topology.h [deleted file]
arch/avr32/include/asm/xor.h [deleted file]
arch/avr32/kernel/process.c
arch/avr32/kernel/time.c
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/board-mtx1.c
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/jump_label.h
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/octeon_switch.S
arch/mips/kernel/prom.c
arch/mips/kernel/r2300_switch.S
arch/mips/kernel/r4k_switch.S
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/include/asm/prom.h
arch/openrisc/kernel/prom.c
arch/openrisc/mm/fault.c
arch/parisc/Kconfig
arch/parisc/configs/712_defconfig
arch/parisc/configs/a500_defconfig
arch/parisc/configs/b180_defconfig
arch/parisc/configs/c3000_defconfig
arch/parisc/configs/c8000_defconfig
arch/parisc/configs/default_defconfig
arch/parisc/include/asm/traps.h
arch/parisc/kernel/smp.c
arch/parisc/kernel/traps.c
arch/parisc/lib/memcpy.c
arch/parisc/mm/fault.c
arch/powerpc/Kconfig
arch/powerpc/boot/Makefile
arch/powerpc/boot/epapr-wrapper.c [new file with mode: 0644]
arch/powerpc/boot/epapr.c
arch/powerpc/boot/of.c
arch/powerpc/boot/wrapper
arch/powerpc/include/asm/device.h
arch/powerpc/include/asm/fsl_pamu_stash.h [new file with mode: 0644]
arch/powerpc/include/asm/irq.h
arch/powerpc/include/asm/jump_label.h
arch/powerpc/include/asm/processor.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/misc_64.S
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/tm.S
arch/powerpc/kernel/vio.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/e500_mmu_host.c
arch/powerpc/lib/checksum_64.S
arch/powerpc/lib/sstep.c
arch/powerpc/mm/fault.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mem.c
arch/powerpc/perf/power8-pmu.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/smp.c
arch/powerpc/sysdev/fsl_pci.h
arch/s390/Kconfig
arch/s390/defconfig
arch/s390/include/asm/irq.h
arch/s390/include/asm/jump_label.h
arch/s390/include/asm/kprobes.h
arch/s390/include/asm/mutex.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/sclp.h
arch/s390/include/asm/spinlock.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.S
arch/s390/kernel/entry.h
arch/s390/kernel/entry64.S
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/Makefile
arch/score/include/asm/checksum.h
arch/score/include/asm/io.h
arch/score/include/asm/pgalloc.h
arch/score/kernel/entry.S
arch/score/kernel/process.c
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/include/asm/floppy_64.h
arch/sparc/include/asm/jump_label.h
arch/sparc/kernel/Makefile
arch/sparc/kernel/ds.c
arch/sparc/kernel/ldc.c
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/atomic.h
arch/tile/include/asm/atomic_32.h
arch/tile/include/asm/cmpxchg.h
arch/tile/include/asm/page.h
arch/tile/include/asm/percpu.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/hardwall.c
arch/tile/kernel/intvec_32.S
arch/tile/kernel/intvec_64.S
arch/tile/kernel/setup.c
arch/tile/kernel/stack.c
arch/tile/kernel/unaligned.c
arch/tile/lib/atomic_32.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/crypto/Makefile
arch/x86/crypto/camellia_glue.c
arch/x86/crypto/crct10dif-pcl-asm_64.S [new file with mode: 0644]
arch/x86/crypto/crct10dif-pclmul_glue.c [new file with mode: 0644]
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/dma-contiguous.h
arch/x86/include/asm/jump_label.h
arch/x86/include/asm/mutex_64.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/tlbflush.h
arch/x86/include/asm/xen/page.h
arch/x86/include/asm/xor_avx.h
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/cpu/mtrr/generic.c
arch/x86/kernel/cpu/perf_event.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/kvm.c
arch/x86/kernel/microcode_amd.c
arch/x86/kernel/reboot.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/sysfb_simplefb.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/pci/mmconfig-shared.c
arch/x86/platform/efi/efi.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-cgroup.c
block/blk-core.c
block/blk-exec.c
block/blk-ioc.c
block/blk-sysfs.c
block/cfq-iosched.c
block/cmdline-parser.c [new file with mode: 0644]
block/compat_ioctl.c
block/deadline-iosched.c
block/elevator.c
block/genhd.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/Kconfig
crypto/Makefile
crypto/aes_generic.c
crypto/api.c
crypto/camellia_generic.c
crypto/cast_common.c
crypto/crct10dif_common.c [new file with mode: 0644]
crypto/crct10dif_generic.c [new file with mode: 0644]
crypto/fcrypt.c
crypto/scatterwalk.c
crypto/tcrypt.c
crypto/testmgr.c
crypto/testmgr.h
drivers/acpi/Kconfig
drivers/acpi/acpi_ipmi.c
drivers/acpi/acpi_lpss.c
drivers/acpi/acpica/exstore.c
drivers/acpi/device_pm.c
drivers/acpi/glue.c
drivers/acpi/power.c
drivers/acpi/scan.c
drivers/ata/ahci.c
drivers/ata/ahci_platform.c
drivers/ata/libahci.c
drivers/ata/libata-acpi.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/libata.h
drivers/ata/pata_isapnp.c
drivers/ata/sata_promise.c
drivers/atm/he.c
drivers/atm/nicstar.c
drivers/base/core.c
drivers/base/dma-buf.c
drivers/base/dma-contiguous.c
drivers/base/memory.c
drivers/base/node.c
drivers/bcma/driver_pci.c
drivers/bcma/scan.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/cpqarray.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/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/bus/mvebu-mbus.c
drivers/char/hw_random/Kconfig
drivers/char/hw_random/mxc-rnga.c
drivers/char/hw_random/omap-rng.c
drivers/char/hw_random/picoxcell-rng.c
drivers/char/hw_random/tx4939-rng.c
drivers/char/hw_random/via-rng.c
drivers/char/random.c
drivers/char/tpm/tpm_tis.c
drivers/char/tpm/xen-tpmfront.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/Kconfig
drivers/clocksource/clksrc-of.c
drivers/clocksource/em_sti.c
drivers/clocksource/exynos_mct.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/acpi-cpufreq.c
drivers/cpufreq/cpufreq-cpu0.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/exynos5440-cpufreq.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/s3c64xx-cpufreq.c
drivers/cpufreq/spear-cpufreq.c
drivers/cpuidle/Kconfig.arm
drivers/cpuidle/Makefile
drivers/cpuidle/cpuidle-big_little.c [new file with mode: 0644]
drivers/cpuidle/driver.c
drivers/crypto/Kconfig
drivers/crypto/amcc/crypto4xx_alg.c
drivers/crypto/caam/Kconfig
drivers/crypto/caam/Makefile
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/caamhash.c
drivers/crypto/caam/ctrl.c
drivers/crypto/caam/desc_constr.h
drivers/crypto/caam/intern.h
drivers/crypto/caam/jr.c
drivers/crypto/caam/jr.h
drivers/crypto/caam/key_gen.c
drivers/crypto/caam/regs.h
drivers/crypto/nx/nx-aes-cbc.c
drivers/crypto/nx/nx-aes-ccm.c
drivers/crypto/nx/nx-aes-ctr.c
drivers/crypto/nx/nx-aes-ecb.c
drivers/crypto/nx/nx-aes-gcm.c
drivers/crypto/nx/nx-aes-xcbc.c
drivers/crypto/nx/nx-sha256.c
drivers/crypto/nx/nx-sha512.c
drivers/crypto/nx/nx.c
drivers/crypto/nx/nx.h
drivers/crypto/omap-aes.c
drivers/crypto/omap-sham.c
drivers/crypto/sahara.c
drivers/crypto/tegra-aes.c
drivers/crypto/ux500/hash/hash_core.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.h
drivers/dma/sh/shdmac.c [moved from drivers/dma/sh/shdma.c with 88% similarity]
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-74x164.c
drivers/gpio/gpio-adnp.c
drivers/gpio/gpio-adp5520.c
drivers/gpio/gpio-adp5588.c
drivers/gpio/gpio-arizona.c
drivers/gpio/gpio-da9052.c
drivers/gpio/gpio-da9055.c
drivers/gpio/gpio-em.c
drivers/gpio/gpio-f7188x.c [new file with mode: 0644]
drivers/gpio/gpio-ich.c
drivers/gpio/gpio-janz-ttl.c
drivers/gpio/gpio-kempld.c [new file with mode: 0644]
drivers/gpio/gpio-lynxpoint.c
drivers/gpio/gpio-max7301.c
drivers/gpio/gpio-max730x.c
drivers/gpio/gpio-max732x.c
drivers/gpio/gpio-mc33880.c
drivers/gpio/gpio-mcp23s08.c
drivers/gpio/gpio-msic.c
drivers/gpio/gpio-msm-v2.c
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpio-octeon.c [new file with mode: 0644]
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-palmas.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-pcf857x.c
drivers/gpio/gpio-pl061.c
drivers/gpio/gpio-pxa.c
drivers/gpio/gpio-rcar.c
drivers/gpio/gpio-rdc321x.c
drivers/gpio/gpio-samsung.c
drivers/gpio/gpio-spear-spics.c
drivers/gpio/gpio-sta2x11.c
drivers/gpio/gpio-sx150x.c
drivers/gpio/gpio-timberdale.c
drivers/gpio/gpio-tps65912.c
drivers/gpio/gpio-ts5500.c
drivers/gpio/gpio-twl4030.c
drivers/gpio/gpio-twl6040.c
drivers/gpio/gpio-tz1090-pdc.c [new file with mode: 0644]
drivers/gpio/gpio-tz1090.c [new file with mode: 0644]
drivers/gpio/gpio-ucb1400.c
drivers/gpio/gpio-wm831x.c
drivers/gpio/gpio-wm8350.c
drivers/gpio/gpio-wm8994.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/ast/ast_drv.h
drivers/gpu/drm/drm_context.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos_drm_buf.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/gma500/gtt.c
drivers/gpu/drm/i2c/tda998x_drv.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_gtt.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_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
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_tv.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem.h
drivers/gpu/drm/msm/msm_gem_submit.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/nouveau/core/subdev/bios/init.c
drivers/gpu/drm/nouveau/core/subdev/mc/base.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/btc_dpm.h
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/evergreen.c
drivers/gpu/drm/radeon/evergreen_hdmi.c
drivers/gpu/drm/radeon/evergreend.h
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.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/r600_hdmi.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_atombios.c
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_ring.c
drivers/gpu/drm/radeon/radeon_test.c
drivers/gpu/drm/radeon/radeon_trace.h
drivers/gpu/drm/radeon/radeon_uvd.c
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/sid.h
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/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/vga/vgaarb.c
drivers/hid/Kconfig
drivers/hid/hid-core.c
drivers/hid/hid-holtek-mouse.c
drivers/hid/hid-ids.h
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-roccat-kone.c
drivers/hid/hid-roccat-koneplus.c
drivers/hid/hid-roccat-kovaplus.c
drivers/hid/hid-roccat-pyra.c
drivers/hid/hid-sony.c
drivers/hid/hid-steelseries.c
drivers/hid/hid-wiimote-core.c
drivers/hid/hid-wiimote-modules.c
drivers/hid/hid-wiimote.h
drivers/hid/hid-zpff.c
drivers/hid/hidraw.c
drivers/hid/uhid.c
drivers/hid/usbhid/hid-quirks.c
drivers/hv/connection.c
drivers/hv/hv_kvp.c
drivers/hv/hv_snapshot.c
drivers/hv/hv_util.c
drivers/hwmon/amc6821.c
drivers/hwmon/applesmc.c
drivers/hwmon/emc2103.c
drivers/hwmon/emc6w201.c
drivers/hwmon/hwmon-vid.c
drivers/hwmon/ibmaem.c
drivers/hwmon/ina2xx.c
drivers/hwmon/k10temp.c
drivers/hwmon/tmp421.c
drivers/hwmon/w83792d.c
drivers/i2c/Kconfig
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-davinci.c
drivers/i2c/busses/i2c-designware-core.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-ismt.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/i2c/busses/i2c-stu300.c
drivers/i2c/i2c-core.c
drivers/i2c/muxes/i2c-arb-gpio-challenge.c
drivers/i2c/muxes/i2c-mux-gpio.c
drivers/i2c/muxes/i2c-mux-pinctrl.c
drivers/iio/Kconfig
drivers/iio/accel/bma180.c
drivers/iio/adc/at91_adc.c
drivers/iio/amplifiers/ad8366.c
drivers/iio/buffer_cb.c
drivers/iio/dac/mcp4725.c
drivers/iio/frequency/adf4350.c
drivers/iio/iio_core.h
drivers/iio/industrialio-buffer.c
drivers/iio/industrialio-core.c
drivers/iio/industrialio-event.c
drivers/iio/magnetometer/st_magn_core.c
drivers/iio/temperature/tmp006.c
drivers/infiniband/hw/amso1100/c2_ae.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/mlx5/srq.c
drivers/infiniband/hw/mthca/mthca_eq.c
drivers/infiniband/hw/ocrdma/ocrdma_hw.c
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/qib/Kconfig
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/evdev.c
drivers/input/joystick/as5011.c
drivers/input/joystick/maplecontrol.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/imx_keypad.c
drivers/input/keyboard/max7359_keypad.c
drivers/input/keyboard/nspire-keypad.c
drivers/input/keyboard/omap4-keypad.c
drivers/input/keyboard/qt1070.c
drivers/input/keyboard/spear-keyboard.c
drivers/input/keyboard/tegra-kbc.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/ideapad_slidebar.c [new file with mode: 0644]
drivers/input/misc/pwm-beeper.c
drivers/input/misc/twl6040-vibra.c
drivers/input/misc/wistron_btns.c
drivers/input/mouse/lifebook.c
drivers/input/mouse/synaptics.c
drivers/input/serio/Kconfig
drivers/input/serio/arc_ps2.c
drivers/input/serio/i8042.h
drivers/input/serio/olpc_apsp.c
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/cy8ctmg110_ts.c
drivers/input/touchscreen/cyttsp4_core.c
drivers/input/touchscreen/eeti_ts.c
drivers/input/touchscreen/htcpen.c
drivers/input/touchscreen/max11801_ts.c
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 [moved from arch/arm/mach-mmp/irq.c with 63% similarity]
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/mailbox/mailbox-omap2.c
drivers/md/Makefile
drivers/md/bcache/bcache.h
drivers/md/bcache/bset.c
drivers/md/bcache/btree.c
drivers/md/bcache/journal.c
drivers/md/bcache/request.c
drivers/md/bcache/sysfs.c
drivers/md/bcache/util.c
drivers/md/bcache/util.h
drivers/md/bcache/writeback.c
drivers/md/dm-bufio.c
drivers/md/dm-cache-target.c
drivers/md/dm-crypt.c
drivers/md/dm-io.c
drivers/md/dm-ioctl.c
drivers/md/dm-kcopyd.c
drivers/md/dm-mpath.c
drivers/md/dm-raid1.c
drivers/md/dm-snap-persistent.c
drivers/md/dm-snap.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/misc/mei/amthif.c
drivers/misc/mei/bus.c
drivers/misc/mei/client.h
drivers/misc/mei/hbm.c
drivers/misc/mei/init.c
drivers/misc/mei/main.c
drivers/misc/mei/mei_dev.h
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_test.c [new file with mode: 0644]
drivers/mtd/tests/mtd_test.h [new file with mode: 0644]
drivers/mtd/tests/nandbiterrs.c [moved from drivers/mtd/tests/mtd_nandbiterrs.c with 93% similarity]
drivers/mtd/tests/oobtest.c [moved from drivers/mtd/tests/mtd_oobtest.c with 90% similarity]
drivers/mtd/tests/pagetest.c [moved from drivers/mtd/tests/mtd_pagetest.c with 63% similarity]
drivers/mtd/tests/readtest.c [moved from drivers/mtd/tests/mtd_readtest.c with 83% similarity]
drivers/mtd/tests/speedtest.c [moved from drivers/mtd/tests/mtd_speedtest.c with 69% similarity]
drivers/mtd/tests/stresstest.c [moved from drivers/mtd/tests/mtd_stresstest.c with 74% similarity]
drivers/mtd/tests/subpagetest.c [moved from drivers/mtd/tests/mtd_subpagetest.c with 86% similarity]
drivers/mtd/tests/torturetest.c [moved from drivers/mtd/tests/mtd_torturetest.c with 90% similarity]
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/can/flexcan.c
drivers/net/can/slcan.c
drivers/net/can/usb/peak_usb/pcan_usb_core.c
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_link.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.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.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/gianfar_ptp.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/igb/igb_ethtool.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/mellanox/mlx5/core/Kconfig
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/eq.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
drivers/net/ethernet/micrel/ks8851_mll.c
drivers/net/ethernet/moxa/moxart_ether.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_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
drivers/net/ethernet/qlogic/qlge/qlge_mpi.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/sfc/Kconfig
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/mcdi.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/ethernet/via/via-rhine.c
drivers/net/ethernet/xilinx/ll_temac_main.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/slip/slip.c
drivers/net/tun.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/dm9601.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/usbnet.c
drivers/net/vxlan.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/brcm80211/Kconfig
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/usb.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/cw1200/cw1200_spi.c
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/11n_aggr.h
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/usb.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/p54/Kconfig
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rtl818x/rtl8187/dev.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/wireless/ti/wl1251/Kconfig
drivers/net/wireless/ti/wlcore/Kconfig
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/base.c
drivers/of/fdt.c
drivers/of/irq.c
drivers/of/of_net.c
drivers/of/platform.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/msi.c
drivers/pci/pci-acpi.c
drivers/pci/pci.c
drivers/pinctrl/pinconf.c
drivers/pinctrl/pinctrl-exynos.c
drivers/pinctrl/pinctrl-palmas.c
drivers/pinctrl/pinctrl-tegra114.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/regulator/da9063-regulator.c
drivers/regulator/palmas-regulator.c
drivers/regulator/ti-abb-regulator.c
drivers/regulator/wm831x-ldo.c
drivers/regulator/wm8350-regulator.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/sclp_cmd.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/spi/spi-atmel.c
drivers/spi/spi-clps711x.c
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-mpc512x-psc.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sh-hspi.c
drivers/staging/android/ashmem.c
drivers/staging/android/logger.c
drivers/staging/android/lowmemorykiller.c
drivers/staging/comedi/Kconfig
drivers/staging/comedi/drivers/ni_65xx.c
drivers/staging/dgap/dgap_driver.c
drivers/staging/dgnc/dgnc_driver.c
drivers/staging/iio/Kconfig
drivers/staging/iio/light/isl29018.c
drivers/staging/iio/magnetometer/hmc5843.c
drivers/staging/iio/meter/ade7854-spi.c
drivers/staging/imx-drm/imx-drm-core.c
drivers/staging/line6/toneport.c
drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h
drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
drivers/staging/lustre/lustre/Kconfig
drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
drivers/staging/lustre/lustre/libcfs/workitem.c
drivers/staging/lustre/lustre/llite/file.c
drivers/staging/lustre/lustre/obdclass/lu_object.c
drivers/staging/lustre/lustre/obdecho/echo_client.c
drivers/staging/lustre/lustre/ptlrpc/pinger.c
drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
drivers/staging/lustre/lustre/ptlrpc/service.c
drivers/staging/octeon-usb/cvmx-usb.c
drivers/staging/octeon/ethernet-mem.c
drivers/staging/octeon/ethernet-rgmii.c
drivers/staging/octeon/ethernet-rx.c
drivers/staging/rtl8188eu/core/rtw_ieee80211.c
drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
drivers/staging/rtl8188eu/core/rtw_mp.c
drivers/staging/rtl8188eu/core/rtw_wlan_util.c
drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
drivers/staging/rtl8188eu/include/odm.h
drivers/staging/rtl8188eu/include/rtl8188e_hal.h
drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
drivers/staging/rtl8188eu/os_dep/usb_intf.c
drivers/staging/rtl8192u/r819xU_cmdpkt.c
drivers/staging/vt6656/card.c
drivers/staging/vt6656/iwctl.c
drivers/staging/vt6656/main_usb.c
drivers/staging/vt6656/rxtx.c
drivers/staging/xillybus/xillybus_core.c
drivers/staging/zram/zram_drv.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/hvc/hvc_xen.c
drivers/tty/n_tty.c
drivers/tty/serial/Kconfig
drivers/tty/serial/imx.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/serial-tegra.c
drivers/tty/serial/vt8500_serial.c
drivers/tty/sysrq.c
drivers/tty/tty_io.c
drivers/tty/tty_ioctl.c
drivers/usb/chipidea/Kconfig
drivers/usb/chipidea/ci_hdrc_imx.c
drivers/usb/chipidea/ci_hdrc_pci.c
drivers/usb/chipidea/core.c
drivers/usb/chipidea/host.c
drivers/usb/chipidea/udc.c
drivers/usb/core/devio.c
drivers/usb/core/hub.c
drivers/usb/core/quirks.c
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/cdc2.c
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/f_ecm.c
drivers/usb/gadget/f_eem.c
drivers/usb/gadget/f_fs.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/fotg210-udc.c
drivers/usb/gadget/fusb300_udc.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/multi.c
drivers/usb/gadget/mv_u3d_core.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/s3c-hsotg.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-grlib.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-mv.c
drivers/usb/host/ehci-octeon.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-pmcmsp.c
drivers/usb/host/ehci-ppc-of.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sead3.c
drivers/usb/host/ehci-sh.c
drivers/usb/host/ehci-tilegx.c
drivers/usb/host/ehci-w90x900.c
drivers/usb/host/ehci-xilinx-of.c
drivers/usb/host/fsl-mph-dr-of.c
drivers/usb/host/imx21-hcd.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-q.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/uhci-pci.c
drivers/usb/host/uhci-q.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/Kconfig
drivers/usb/musb/Kconfig
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_virthub.c
drivers/usb/phy/phy-gpio-vbus-usb.c
drivers/usb/phy/phy-omap-usb3.c
drivers/usb/renesas_usbhs/Kconfig
drivers/usb/serial/Kconfig
drivers/usb/serial/option.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/storage/scsiglue.c
drivers/usb/storage/unusual_devs.h
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/vfio/vfio_iommu_type1.c
drivers/vhost/scsi.c
drivers/vhost/vhost.c
drivers/video/acornfb.c
drivers/video/acornfb.h
drivers/video/logo/logo_linux_clut224.ppm
drivers/video/mmp/hw/mmp_ctrl.c
drivers/video/mxsfb.c
drivers/video/neofb.c
drivers/video/of_display_timing.c
drivers/video/omap2/displays-new/Kconfig
drivers/video/omap2/displays-new/connector-analog-tv.c
drivers/video/omap2/displays-new/connector-dvi.c
drivers/video/omap2/displays-new/connector-hdmi.c
drivers/video/omap2/dss/dispc.c
drivers/video/ps3fb.c
drivers/video/s3fb.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/kempld_wdt.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/binfmt_elf.c
fs/bio-integrity.c
fs/bio.c
fs/block_dev.c
fs/btrfs/Kconfig
fs/btrfs/Makefile
fs/btrfs/async-thread.c
fs/btrfs/async-thread.h
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/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/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/buffer.c
fs/cachefiles/interface.c
fs/cachefiles/internal.h
fs/cachefiles/namei.c
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/Makefile
fs/cifs/cifs_unicode.h
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
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/fscache.c
fs/cifs/fscache.h
fs/cifs/inode.c
fs/cifs/link.c
fs/cifs/misc.c
fs/cifs/netmisc.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/smbfsctl.h
fs/cifs/transport.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/ext3/namei.c
fs/ext4/extents_status.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/xattr.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/dentry.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/nfs4file.c
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4filelayoutdev.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/nilfs2/page.c
fs/nilfs2/segment.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/dcache.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/super.c
fs/ocfs2/xattr.c
fs/ocfs2/xattr.h
fs/omfs/file.c
fs/open.c
fs/pnode.h
fs/proc/fd.c
fs/proc/inode.c
fs/proc/meminfo.c
fs/proc/root.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/reiserfs/journal.c
fs/squashfs/block.c
fs/squashfs/dir.c
fs/squashfs/namei.c
fs/squashfs/squashfs_fs.h
fs/statfs.c
fs/super.c
fs/sysfs/dir.c
fs/sysfs/mount.c
fs/sysv/itree.c
fs/sysv/super.c
fs/ubifs/debug.c
fs/ubifs/shrinker.c
fs/ubifs/super.c
fs/ubifs/ubifs.h
fs/udf/file.c
fs/udf/ialloc.c
fs/udf/inode.c
fs/udf/super.c
fs/udf/udf_sb.h
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/acpi/acpi_bus.h
include/asm-generic/dma-contiguous.h [deleted file]
include/asm-generic/hugetlb.h
include/asm-generic/vtime.h
include/crypto/scatterwalk.h
include/drm/drmP.h
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/dt-bindings/pinctrl/omap.h
include/linux/aio.h
include/linux/amba/pl080.h
include/linux/anon_inodes.h
include/linux/backing-dev.h
include/linux/balloon_compaction.h
include/linux/bcma/bcma_driver_pci.h
include/linux/binfmts.h
include/linux/blkdev.h
include/linux/capability.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/compiler-gcc4.h
include/linux/cpu_rmap.h
include/linux/cpufreq.h
include/linux/crash_dump.h
include/linux/crc-t10dif.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/hyperv.h
include/linux/i8042.h
include/linux/init.h
include/linux/intel-iommu.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.h
include/linux/kernel_stat.h
include/linux/kobject_ns.h
include/linux/kprobes.h
include/linux/kvm_host.h
include/linux/list_lru.h [new file with mode: 0644]
include/linux/lockref.h
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/miscdevice.h
include/linux/mlx5/device.h
include/linux/mlx5/driver.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/mod_devicetable.h
include/linux/mount.h
include/linux/mtd/bbm.h
include/linux/mtd/fsmc.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mutex.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_irq.h
include/linux/of_net.h
include/linux/pci_ids.h
include/linux/percpu_ida.h [new file with mode: 0644]
include/linux/perf_event.h
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/gpio-em.h
include/linux/platform_data/leds-lp55xx.h
include/linux/platform_data/leds-pca963x.h [moved from include/linux/platform_data/leds-pca9633.h with 66% similarity]
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/random.h
include/linux/rbtree.h
include/linux/regulator/driver.h
include/linux/res_counter.h
include/linux/sched.h
include/linux/security.h
include/linux/seqlock.h
include/linux/sh_dma.h
include/linux/shdma-base.h
include/linux/shrinker.h
include/linux/skbuff.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/usb/usb_phy_gen_xceiv.h
include/linux/usb/usbnet.h
include/linux/usb_usual.h
include/linux/user_namespace.h
include/linux/vfio.h
include/linux/vm_event_item.h
include/linux/vmstat.h
include/linux/writeback.h
include/linux/xattr.h
include/net/9p/client.h
include/net/addrconf.h
include/net/bluetooth/hci.h
include/net/ip.h
include/net/ip_vs.h
include/net/mrp.h
include/net/ndisc.h
include/net/net_namespace.h
include/net/netfilter/nf_conntrack_extend.h
include/net/netfilter/nf_conntrack_synproxy.h
include/net/secure_seq.h
include/net/sock.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/block.h
include/trace/events/btrfs.h
include/trace/events/kmem.h
include/trace/events/sunrpc.h
include/trace/events/vmscan.h
include/uapi/drm/drm_mode.h
include/uapi/drm/radeon_drm.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/reiserfs_xattr.h
include/uapi/linux/vfio.h
init/Kconfig
init/do_mounts.c
init/main.c
ipc/msg.c
ipc/namespace.c
ipc/sem.c
ipc/shm.c
ipc/util.c
ipc/util.h
kernel/Makefile
kernel/audit.c
kernel/capability.c
kernel/cgroup.c
kernel/context_tracking.c
kernel/events/core.c
kernel/events/uprobes.c
kernel/extable.c
kernel/fork.c
kernel/gcov/fs.c
kernel/groups.c
kernel/irq/Kconfig
kernel/kexec.c
kernel/kmod.c
kernel/kprobes.c
kernel/ksysfs.c
kernel/modsign_pubkey.c
kernel/nsproxy.c
kernel/padata.c
kernel/panic.c
kernel/params.c
kernel/pid.c
kernel/pid_namespace.c
kernel/power/hibernate.c
kernel/power/snapshot.c
kernel/power/user.c
kernel/ptrace.c
kernel/rcupdate.c
kernel/reboot.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/sys.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/uid16.c
kernel/up.c
kernel/user.c
kernel/user_namespace.c
kernel/utsname.c
kernel/watchdog.c
lib/Kconfig
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/hexdump.c
lib/kobject.c
lib/lockref.c
lib/lz4/lz4_decompress.c
lib/percpu-refcount.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/bounce.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/mprotect.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/802/mrp.c
net/9p/client.c
net/9p/trans_virtio.c
net/Kconfig
net/batman-adv/soft-interface.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/bluetooth/rfcomm/tty.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/dev.c
net/core/flow_dissector.c
net/core/net-sysfs.c
net/core/net_namespace.c
net/core/netpoll.c
net/core/scm.c
net/core/secure_seq.c
net/dccp/ipv6.c
net/ipv4/af_inet.c
net/ipv4/igmp.c
net/ipv4/inetpeer.c
net/ipv4/ip_output.c
net/ipv4/ip_tunnel.c
net/ipv4/ip_tunnel_core.c
net/ipv4/ipmr.c
net/ipv4/netfilter/ipt_SYNPROXY.c
net/ipv4/raw.c
net/ipv4/tcp_input.c
net/ipv4/tcp_memcontrol.c
net/ipv4/tcp_metrics.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv4/xfrm4_mode_tunnel.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/exthdrs.c
net/ipv6/fib6_rules.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/mcast.c
net/ipv6/ndisc.c
net/ipv6/netfilter/ip6t_SYNPROXY.c
net/ipv6/netfilter/nf_nat_proto_icmpv6.c
net/ipv6/raw.c
net/ipv6/sit.c
net/ipv6/udp.c
net/lapb/lapb_timer.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_core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_est.c
net/netfilter/ipvs/ip_vs_lblc.c
net/netfilter/ipvs/ip_vs_lblcr.c
net/netfilter/ipvs/ip_vs_nq.c
net/netfilter/ipvs/ip_vs_sed.c
net/netfilter/ipvs/ip_vs_wlc.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_synproxy_core.c
net/netfilter/nfnetlink_queue_core.c
net/netlink/af_netlink.c
net/openvswitch/flow.c
net/sched/sch_fq.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/sysctl_net.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
security/apparmor/Kconfig
security/apparmor/Makefile
security/apparmor/apparmorfs.c
security/apparmor/capability.c
security/apparmor/context.c
security/apparmor/crypto.c [new file with mode: 0644]
security/apparmor/domain.c
security/apparmor/include/apparmor.h
security/apparmor/include/apparmorfs.h
security/apparmor/include/audit.h
security/apparmor/include/capability.h
security/apparmor/include/context.h
security/apparmor/include/crypto.h [new file with mode: 0644]
security/apparmor/include/policy.h
security/apparmor/include/policy_unpack.h
security/apparmor/lib.c
security/apparmor/lsm.c
security/apparmor/policy.c
security/apparmor/policy_unpack.c
security/apparmor/procattr.c
security/capability.c
security/commoncap.c
security/integrity/evm/evm_main.c
security/security.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/avc.h
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c
sound/core/compress_offload.c
sound/pci/ac97/ac97_codec.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/rme9652/hdsp.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/blackfin/bf6xx-i2s.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/max98095.c
sound/soc/codecs/mc13783.c
sound/soc/fsl/Kconfig
sound/soc/fsl/imx-audmux.c
sound/soc/fsl/imx-sgtl5000.c
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/samsung/Kconfig
sound/soc/sh/rcar/scu.c
sound/soc/soc-core.c
sound/usb/usx2y/us122l.c
sound/usb/usx2y/usbusx2yaudio.c
sound/usb/usx2y/usx2yhwdeppcm.c
tools/lguest/lguest.c
tools/lib/lk/debugfs.c
tools/perf/Makefile
tools/perf/arch/x86/util/tsc.c
tools/perf/builtin-annotate.c
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-kvm.c
tools/perf/builtin-mem.c
tools/perf/builtin-report.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-trace.c
tools/perf/config/Makefile
tools/perf/config/feature-tests.mak
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/annotate.c
tools/perf/util/build-id.c
tools/perf/util/dwarf-aux.c
tools/perf/util/dwarf-aux.h
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/hist.c
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/map.c
tools/perf/util/map.h
tools/perf/util/probe-finder.c
tools/perf/util/probe-finder.h
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/symbol-elf.c
tools/perf/util/tool.h
tools/perf/util/trace-event-parse.c
tools/testing/selftests/timers/posix_timers.c
tools/virtio/.gitignore [new file with mode: 0644]
virt/kvm/async_pf.c
virt/kvm/kvm_main.c

diff --git a/CREDITS b/CREDITS
index 9416a9a8b95e6c4404c80ade376feff7b6df406a..0640e16504832e43c2d3b9bb82b6b5fe3f5bea48 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2808,8 +2808,7 @@ S: Ottawa, Ontario
 S: Canada K2P 0X8
 
 N: Mikael Pettersson
-E: mikpe@it.uu.se
-W: http://user.it.uu.se/~mikpe/linux/
+E: mikpelinux@gmail.com
 D: Miscellaneous fixes
 
 N: Reed H. Petty
index 2be603c52a240fa55f1a630d4f3567cc9c134d19..a6b68572474062bf04329a434cb27bbf825d19b8 100644 (file)
@@ -37,8 +37,8 @@ Description:
                that the USB device has been connected to the machine.  This
                file is read-only.
 Users:
-               PowerTOP <power@bughost.org>
-               http://www.lesswatts.org/projects/powertop/
+               PowerTOP <powertop@lists.01.org>
+               https://01.org/powertop/
 
 What:          /sys/bus/usb/device/.../power/active_duration
 Date:          January 2008
@@ -57,8 +57,8 @@ Description:
                will give an integer percentage.  Note that this does not
                account for counter wrap.
 Users:
-               PowerTOP <power@bughost.org>
-               http://www.lesswatts.org/projects/powertop/
+               PowerTOP <powertop@lists.01.org>
+               https://01.org/powertop/
 
 What:          /sys/bus/usb/devices/<busnum>-<port[.port]>...:<config num>-<interface num>/supports_autosuspend
 Date:          January 2008
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 9d43e76708413bdf6b3d25a0b1179714b06680ba..efe449bdf811db7a1c9f74f38a0371d2c0dd692e 100644 (file)
@@ -1,6 +1,6 @@
 What:          /sys/devices/.../power/
 Date:          January 2009
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../power directory contains attributes
                allowing the user space to check and modify some power
@@ -8,7 +8,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup
 Date:          January 2009
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../power/wakeup attribute allows the user
                space to check if the device is enabled to wake up the system
@@ -34,7 +34,7 @@ Description:
 
 What:          /sys/devices/.../power/control
 Date:          January 2009
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../power/control attribute allows the user
                space to control the run-time power management of the device.
@@ -53,7 +53,7 @@ Description:
 
 What:          /sys/devices/.../power/async
 Date:          January 2009
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../async attribute allows the user space to
                enable or diasble the device's suspend and resume callbacks to
@@ -79,7 +79,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_count
 Date:          September 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_count attribute contains the number
                of signaled wakeup events associated with the device.  This
@@ -88,7 +88,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_active_count
 Date:          September 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_active_count attribute contains the
                number of times the processing of wakeup events associated with
@@ -98,7 +98,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_abort_count
 Date:          February 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_abort_count attribute contains the
                number of times the processing of a wakeup event associated with
@@ -109,7 +109,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_expire_count
 Date:          February 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_expire_count attribute contains the
                number of times a wakeup event associated with the device has
@@ -119,7 +119,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_active
 Date:          September 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_active attribute contains either 1,
                or 0, depending on whether or not a wakeup event associated with
@@ -129,7 +129,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_total_time_ms
 Date:          September 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_total_time_ms attribute contains
                the total time of processing wakeup events associated with the
@@ -139,7 +139,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_max_time_ms
 Date:          September 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_max_time_ms attribute contains
                the maximum time of processing a single wakeup event associated
@@ -149,7 +149,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_last_time_ms
 Date:          September 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_last_time_ms attribute contains
                the value of the monotonic clock corresponding to the time of
@@ -160,7 +160,7 @@ Description:
 
 What:          /sys/devices/.../power/wakeup_prevent_sleep_time_ms
 Date:          February 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../wakeup_prevent_sleep_time_ms attribute
                contains the total time the device has been preventing
@@ -189,7 +189,7 @@ Description:
 
 What:          /sys/devices/.../power/pm_qos_latency_us
 Date:          March 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../power/pm_qos_resume_latency_us attribute
                contains the PM QoS resume latency limit for the given device,
@@ -207,7 +207,7 @@ Description:
 
 What:          /sys/devices/.../power/pm_qos_no_power_off
 Date:          September 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../power/pm_qos_no_power_off attribute
                is used for manipulating the PM QoS "no power off" flag.  If
@@ -222,7 +222,7 @@ Description:
 
 What:          /sys/devices/.../power/pm_qos_remote_wakeup
 Date:          September 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/devices/.../power/pm_qos_remote_wakeup attribute
                is used for manipulating the PM QoS "remote wakeup required"
index 217772615d0288f996e05cc128b98c9a40d95042..205a7387844106804de496ec9b3a8c372b725977 100644 (file)
@@ -1,6 +1,6 @@
 What:          /sys/power/
 Date:          August 2006
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power directory will contain files that will
                provide a unified interface to the power management
@@ -8,7 +8,7 @@ Description:
 
 What:          /sys/power/state
 Date:          August 2006
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/state file controls the system power state.
                Reading from this file returns what states are supported,
@@ -22,7 +22,7 @@ Description:
 
 What:          /sys/power/disk
 Date:          September 2006
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/disk file controls the operating mode of the
                suspend-to-disk mechanism.  Reading from this file returns
@@ -67,7 +67,7 @@ Description:
 
 What:          /sys/power/image_size
 Date:          August 2006
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/image_size file controls the size of the image
                created by the suspend-to-disk mechanism.  It can be written a
@@ -84,7 +84,7 @@ Description:
 
 What:          /sys/power/pm_trace
 Date:          August 2006
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/pm_trace file controls the code which saves the
                last PM event point in the RTC across reboots, so that you can
@@ -133,7 +133,7 @@ Description:
 
 What:          /sys/power/pm_async
 Date:          January 2009
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/pm_async file controls the switch allowing the
                user space to enable or disable asynchronous suspend and resume
@@ -146,7 +146,7 @@ Description:
 
 What:          /sys/power/wakeup_count
 Date:          July 2010
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/wakeup_count file allows user space to put the
                system into a sleep state while taking into account the
@@ -161,7 +161,7 @@ Description:
 
 What:          /sys/power/reserved_size
 Date:          May 2011
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/reserved_size file allows user space to control
                the amount of memory reserved for allocations made by device
@@ -175,7 +175,7 @@ Description:
 
 What:          /sys/power/autosleep
 Date:          April 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/autosleep file can be written one of the strings
                returned by reads from /sys/power/state.  If that happens, a
@@ -192,7 +192,7 @@ Description:
 
 What:          /sys/power/wake_lock
 Date:          February 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/wake_lock file allows user space to create
                wakeup source objects and activate them on demand (if one of
@@ -219,7 +219,7 @@ Description:
 
 What:          /sys/power/wake_unlock
 Date:          February 2012
-Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/wake_unlock file allows user space to deactivate
                wakeup sources created with the help of /sys/power/wake_lock.
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 febbb1ba4d2317b984e7217796ac39151f867531..784841caa6e63824ff2503351fb12e682f01e3b3 100644 (file)
@@ -4,4 +4,4 @@ CONFIG_ACPI_CUSTOM_DSDT builds the image into the kernel.
 
 When to use this method is described in detail on the
 Linux/ACPI home page:
-http://www.lesswatts.org/projects/acpi/overridingDSDT.php
+https://01.org/linux-acpi/documentation/overriding-dsdt
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"
index 264e9841563aa6ebb162b545fb3442b85f00c38b..d9995f1f51b3eb9e678a557a471e4d387db49ca8 100644 (file)
@@ -18,17 +18,17 @@ this byte for application use, with the following caveats:
            parameters containing user virtual addresses *must* have
            their top byte cleared before trapping to the kernel.
 
-       (2) Tags are not guaranteed to be preserved when delivering
-           signals. This means that signal handlers in applications
-           making use of tags cannot rely on the tag information for
-           user virtual addresses being maintained for fields inside
-           siginfo_t. One exception to this rule is for signals raised
-           in response to debug exceptions, where the tag information
+       (2) Non-zero tags are not preserved when delivering signals.
+           This means that signal handlers in applications making use
+           of tags cannot rely on the tag information for user virtual
+           addresses being maintained for fields inside siginfo_t.
+           One exception to this rule is for signals raised in response
+           to watchpoint debug exceptions, where the tag information
            will be preserved.
 
        (3) Special care should be taken when using tagged pointers,
            since it is likely that C compilers will not hazard two
-           addresses differing only in the upper bits.
+           virtual addresses differing only in the upper byte.
 
 The architecture prevents the use of a tagged PC, so the upper byte will
 be set to a sign-extension of bit 55 on exception return.
index d18ecd827c408d0fb42a8d8a7fc669ce88c95fc2..929d9904f74b7eb94bac71e81308b0bf335c3108 100644 (file)
@@ -6,6 +6,8 @@ capability.txt
        - Generic Block Device Capability (/sys/block/<device>/capability)
 cfq-iosched.txt
        - CFQ IO scheduler tunables
+cmdline-partition.txt
+       - how to specify block device partitions on kernel command line
 data-integrity.txt
        - Block data integrity
 deadline-iosched.txt
diff --git a/Documentation/block/cmdline-partition.txt b/Documentation/block/cmdline-partition.txt
new file mode 100644 (file)
index 0000000..525b9f6
--- /dev/null
@@ -0,0 +1,39 @@
+Embedded device command line partition parsing
+=====================================================================
+
+Support for reading the block device partition table from the command line.
+It is typically used for fixed block (eMMC) embedded devices.
+It has no MBR, so saves 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 629d0ef17308a73c4f06e108218de8b7e7b4cb16..daa30174bcc13941e7454772dc2827c377a02a4b 100644 (file)
@@ -3,10 +3,17 @@ Microchip MCP2308/MCP23S08/MCP23017/MCP23S17 driver for
 
 Required properties:
 - compatible : Should be
-    - "mcp,mcp23s08" for  8 GPIO SPI version
-    - "mcp,mcp23s17" for 16 GPIO SPI version
-    - "mcp,mcp23008" for  8 GPIO I2C version or
-    - "mcp,mcp23017" for 16 GPIO I2C version of the chip
+    - "mcp,mcp23s08" (DEPRECATED) for  8 GPIO SPI version
+    - "mcp,mcp23s17" (DEPRECATED) for 16 GPIO SPI version
+    - "mcp,mcp23008" (DEPRECATED) for  8 GPIO I2C version or
+    - "mcp,mcp23017" (DEPRECATED) for 16 GPIO I2C version of the chip
+
+    - "microchip,mcp23s08" for  8 GPIO SPI version
+    - "microchip,mcp23s17" for 16 GPIO SPI version
+    - "microchip,mcp23008" for  8 GPIO I2C version or
+    - "microchip,mcp23017" for 16 GPIO I2C version of the chip
+    NOTE: Do not use the old mcp prefix any more. It is deprecated and will be
+    removed.
 - #gpio-cells : Should be two.
   - first cell is the pin number
   - second cell is used to specify flags. Flags are currently unused.
@@ -15,10 +22,11 @@ Required properties:
         SPI uses this to specify the chipselect line which the chip is
         connected to. The driver and the SPI variant of the chip support
         multiple chips on the same chipselect. Have a look at
-        mcp,spi-present-mask below.
+        microchip,spi-present-mask below.
 
 Required device specific properties (only for SPI chips):
-- mcp,spi-present-mask : This is a present flag, that makes only sense for SPI
+- mcp,spi-present-mask (DEPRECATED)
+- microchip,spi-present-mask : This is a present flag, that makes only sense for SPI
         chips - as the name suggests. Multiple SPI chips can share the same
         SPI chipselect. Set a bit in bit0-7 in this mask to 1 if there is a
         chip connected with the corresponding spi address set. For example if
@@ -26,11 +34,13 @@ Required device specific properties (only for SPI chips):
         which is 0x08. mcp23s08 chip variant only supports bits 0-3. It is not
         possible to mix mcp23s08 and mcp23s17 on the same chipselect. Set at
         least one bit to 1 for SPI chips.
+    NOTE: Do not use the old mcp prefix any more. It is deprecated and will be
+    removed.
 - spi-max-frequency = The maximum frequency this chip is able to handle
 
 Example I2C:
 gpiom1: gpio@20 {
-        compatible = "mcp,mcp23017";
+        compatible = "microchip,mcp23017";
         gpio-controller;
         #gpio-cells = <2>;
         reg = <0x20>;
@@ -38,7 +48,7 @@ gpiom1: gpio@20 {
 
 Example SPI:
 gpiom1: gpio@0 {
-        compatible = "mcp,mcp23s17";
+        compatible = "microchip,mcp23s17";
         gpio-controller;
         #gpio-cells = <2>;
         spi-present-mask = <0x01>;
diff --git a/Documentation/devicetree/bindings/gpio/gpio-palmas.txt b/Documentation/devicetree/bindings/gpio/gpio-palmas.txt
new file mode 100644 (file)
index 0000000..08b5b52
--- /dev/null
@@ -0,0 +1,27 @@
+Palmas GPIO controller bindings
+
+Required properties:
+- compatible:
+  - "ti,palams-gpio" for palma series of the GPIO controller
+  - "ti,tps80036-gpio" for Palma series device TPS80036.
+  - "ti,tps65913-gpio" for palma series device TPS65913.
+  - "ti,tps65914-gpio" for palma series device TPS65914.
+- #gpio-cells : Should be two.
+  - first cell is the gpio pin number
+  - second cell is used to specify the gpio polarity:
+      0 = active high
+      1 = active low
+- gpio-controller : Marks the device node as a GPIO controller.
+
+Note: This gpio node will be sub node of palmas node.
+
+Example:
+       palmas: tps65913@58 {
+               :::::::::::
+               palmas_gpio: palmas_gpio {
+                       compatible = "ti,palmas-gpio";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+               :::::::::::
+       };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-tz1090-pdc.txt b/Documentation/devicetree/bindings/gpio/gpio-tz1090-pdc.txt
new file mode 100644 (file)
index 0000000..1fd98ff
--- /dev/null
@@ -0,0 +1,45 @@
+ImgTec TZ1090 PDC GPIO Controller
+
+Required properties:
+- compatible: Compatible property value should be "img,tz1090-pdc-gpio".
+
+- reg: Physical base address of the controller and length of memory mapped
+  region. This starts at and cover the SOC_GPIO_CONTROL registers.
+
+- gpio-controller: Specifies that the node is a gpio controller.
+
+- #gpio-cells: Should be 2. The syntax of the gpio specifier used by client
+  nodes should have the following values.
+     <[phandle of the gpio controller node]
+      [PDC gpio number]
+      [gpio flags]>
+
+  Values for gpio specifier:
+  - GPIO number: a value in the range 0 to 6.
+  - GPIO flags: bit field of flags, as defined in <dt-bindings/gpio/gpio.h>.
+    Only the following flags are supported:
+      GPIO_ACTIVE_HIGH
+      GPIO_ACTIVE_LOW
+
+Optional properties:
+- gpio-ranges: Mapping to pin controller pins (as described in
+  Documentation/devicetree/bindings/gpio/gpio.txt)
+
+- interrupts: Individual syswake interrupts (other GPIOs cannot interrupt)
+
+
+Example:
+
+       pdc_gpios: gpio-controller@02006500 {
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               compatible = "img,tz1090-pdc-gpio";
+               reg = <0x02006500 0x100>;
+
+               interrupt-parent = <&pdc>;
+               interrupts =    <8  IRQ_TYPE_NONE>,     /* Syswake 0 */
+                               <9  IRQ_TYPE_NONE>,     /* Syswake 1 */
+                               <10 IRQ_TYPE_NONE>;     /* Syswake 2 */
+               gpio-ranges = <&pdc_pinctrl 0 0 7>;
+       };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-tz1090.txt b/Documentation/devicetree/bindings/gpio/gpio-tz1090.txt
new file mode 100644 (file)
index 0000000..174cdf3
--- /dev/null
@@ -0,0 +1,88 @@
+ImgTec TZ1090 GPIO Controller
+
+Required properties:
+- compatible: Compatible property value should be "img,tz1090-gpio".
+
+- reg: Physical base address of the controller and length of memory mapped
+  region.
+
+- #address-cells: Should be 1 (for bank subnodes)
+
+- #size-cells: Should be 0 (for bank subnodes)
+
+- Each bank of GPIOs should have a subnode to represent it.
+
+  Bank subnode required properties:
+  - reg: Index of bank in the range 0 to 2.
+
+  - gpio-controller: Specifies that the node is a gpio controller.
+
+  - #gpio-cells: Should be 2. The syntax of the gpio specifier used by client
+    nodes should have the following values.
+       <[phandle of the gpio controller node]
+        [gpio number within the gpio bank]
+        [gpio flags]>
+
+    Values for gpio specifier:
+    - GPIO number: a value in the range 0 to 29.
+    - GPIO flags: bit field of flags, as defined in <dt-bindings/gpio/gpio.h>.
+      Only the following flags are supported:
+        GPIO_ACTIVE_HIGH
+        GPIO_ACTIVE_LOW
+
+  Bank subnode optional properties:
+  - gpio-ranges: Mapping to pin controller pins (as described in
+    Documentation/devicetree/bindings/gpio/gpio.txt)
+
+  - interrupts: Interrupt for the entire bank
+
+  - interrupt-controller: Specifies that the node is an interrupt controller
+
+  - #interrupt-cells: Should be 2. The syntax of the interrupt specifier used by
+    client nodes should have the following values.
+       <[phandle of the interurupt controller]
+        [gpio number within the gpio bank]
+        [irq flags]>
+
+    Values for irq specifier:
+    - GPIO number: a value in the range 0 to 29
+    - IRQ flags: value to describe edge and level triggering, as defined in
+      <dt-bindings/interrupt-controller/irq.h>. Only the following flags are
+      supported:
+        IRQ_TYPE_EDGE_RISING
+        IRQ_TYPE_EDGE_FALLING
+        IRQ_TYPE_EDGE_BOTH
+        IRQ_TYPE_LEVEL_HIGH
+        IRQ_TYPE_LEVEL_LOW
+
+
+
+Example:
+
+       gpios: gpio-controller@02005800 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "img,tz1090-gpio";
+               reg = <0x02005800 0x90>;
+
+               /* bank 0 with an interrupt */
+               gpios0: bank@0 {
+                       #gpio-cells = <2>;
+                       #interrupt-cells = <2>;
+                       reg = <0>;
+                       interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
+                       gpio-controller;
+                       gpio-ranges = <&pinctrl 0 0 30>;
+                       interrupt-controller;
+               };
+
+               /* bank 2 without interrupt */
+               gpios2: bank@2 {
+                       #gpio-cells = <2>;
+                       reg = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pinctrl 0 60 30>;
+               };
+       };
+
+
index 9b3f1d4a88d69fa931ca819c4776727435512104..66416261e14df5a0b621a52ead96e4ef52482472 100644 (file)
@@ -10,8 +10,9 @@ Required properties:
   There're three gpio interrupts in arch-pxa, and they're gpio0,
   gpio1 and gpio_mux. There're only one gpio interrupt in arch-mmp,
   gpio_mux.
-- interrupt-name : Should be the name of irq resource. Each interrupt
-  binds its interrupt-name.
+- interrupt-names : Should be the names of irq resources. Each interrupt
+  uses its own interrupt name, so there should be as many interrupt names
+  as referenced interrups.
 - interrupt-controller : Identifies the node as an interrupt controller.
 - #interrupt-cells: Specifies the number of cells needed to encode an
   interrupt source.
@@ -24,7 +25,7 @@ Example:
                compatible = "marvell,mmp-gpio";
                reg = <0xd4019000 0x1000>;
                interrupts = <49>;
-               interrupt-name = "gpio_mux";
+               interrupt-names = "gpio_mux";
                gpio-controller;
                #gpio-cells = <1>;
                interrupt-controller;
index cb3dc7bcd8e69f975279e2d91d8d87101f909672..8655df9440d506986225dad0594d045054a96728 100644 (file)
@@ -23,6 +23,10 @@ Required Properties:
 Please refer to gpio.txt in this directory for details of gpio-ranges property
 and the common GPIO bindings used by client devices.
 
+The GPIO controller also acts as an interrupt controller. It uses the default
+two cells specifier as described in Documentation/devicetree/bindings/
+interrupt-controller/interrupts.txt.
+
 Example: R8A7779 (R-Car H1) GPIO controller nodes
 
        gpio0: gpio@ffc40000 {
@@ -33,6 +37,8 @@ Example: R8A7779 (R-Car H1) GPIO controller nodes
                #gpio-cells = <2>;
                gpio-controller;
                gpio-ranges = <&pfc 0 0 32>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
        };
        ...
        gpio6: gpio@ffc46000 {
@@ -43,4 +49,6 @@ Example: R8A7779 (R-Car H1) GPIO controller nodes
                #gpio-cells = <2>;
                gpio-controller;
                gpio-ranges = <&pfc 0 192 9>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
        };
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 {
diff --git a/Documentation/devicetree/bindings/input/input-reset.txt b/Documentation/devicetree/bindings/input/input-reset.txt
new file mode 100644 (file)
index 0000000..2bb2626
--- /dev/null
@@ -0,0 +1,33 @@
+Input: sysrq reset sequence
+
+A simple binding to represent a set of keys as described in
+include/uapi/linux/input.h. This is to communicate a sequence of keys to the
+sysrq driver. Upon holding the keys for a specified amount of time (if
+specified) the system is sync'ed and reset.
+
+Key sequences are global to the system but all the keys in a set must be coming
+from the same input device.
+
+The /chosen node should contain a 'linux,sysrq-reset-seq' child node to define
+a set of keys.
+
+Required property:
+sysrq-reset-seq: array of Linux keycodes, one keycode per cell.
+
+Optional property:
+timeout-ms: duration keys must be pressed together in milliseconds before
+generating a sysrq. If omitted the system is rebooted immediately when a valid
+sequence has been recognized.
+
+Example:
+
+ chosen {
+                linux,sysrq-reset-seq {
+                        keyset = <0x03
+                                  0x04
+                                  0x0a>;
+                        timeout-ms = <3000>;
+                };
+         };
+
+Would represent KEY_2, KEY_3 and KEY_9.
index df70318a617f0d36baad2e0a757a33c627bfb1db..49fa14ed155ca282dd63068a0bbe15d739a5cd86 100644 (file)
@@ -6,7 +6,7 @@ Required properties:
 - interrupt-parent: the phandle for the interrupt controller
 - interrupts: touch controller interrupt
 - wakeup-gpios: the gpio pin to be used for waking up the controller
-  as well as uased as irq pin
+  and also used as irq pin
 
 Example:
 
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/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 6d1c0988cfc7c7a0466d9f0cc18cc7feacdb0d2b..c67b975c89063f51fa20ae563f601c7c6113fe08 100644 (file)
@@ -1,11 +1,11 @@
-* Samsung Exynos specific extensions to the Synopsis Designware Mobile
+* Samsung Exynos specific extensions to the Synopsys Designware Mobile
   Storage Host Controller
 
-The Synopsis designware mobile storage host controller is used to interface
+The Synopsys designware mobile storage host controller is used to interface
 a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
-differences between the core Synopsis dw mshc controller properties described
-by synopsis-dw-mshc.txt and the properties used by the Samsung Exynos specific
-extensions to the Synopsis Designware Mobile Storage Host Controller.
+differences between the core Synopsys dw mshc controller properties described
+by synopsys-dw-mshc.txt and the properties used by the Samsung Exynos specific
+extensions to the Synopsys Designware Mobile Storage Host Controller.
 
 Required Properties:
 
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 8a3d91d47b6af2e3e99d6182e25f21007b129f94..c559f3f36309e57f1eccda86e926771047960cbb 100644 (file)
@@ -1,11 +1,11 @@
-* Rockchip specific extensions to the Synopsis Designware Mobile
+* Rockchip specific extensions to the Synopsys Designware Mobile
   Storage Host Controller
 
-The Synopsis designware mobile storage host controller is used to interface
+The Synopsys designware mobile storage host controller is used to interface
 a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
-differences between the core Synopsis dw mshc controller properties described
-by synopsis-dw-mshc.txt and the properties used by the Rockchip specific
-extensions to the Synopsis Designware Mobile Storage Host Controller.
+differences between the core Synopsys dw mshc controller properties described
+by synopsys-dw-mshc.txt and the properties used by the Rockchip specific
+extensions to the Synopsys Designware Mobile Storage Host Controller.
 
 Required Properties:
 
similarity index 93%
rename from Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt
rename to Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
index cdcebea9c6f55f55e87f7647d2d8670c04e470b4..066a78b034ca8589e4de4d31183075768496f81a 100644 (file)
@@ -1,14 +1,14 @@
-* Synopsis Designware Mobile Storage Host Controller
+* Synopsys Designware Mobile Storage Host Controller
 
-The Synopsis designware mobile storage host controller is used to interface
+The Synopsys designware mobile storage host controller is used to interface
 a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
 differences between the core mmc properties described by mmc.txt and the
-properties used by the Synopsis Designware Mobile Storage Host Controller.
+properties used by the Synopsys Designware Mobile Storage Host Controller.
 
 Required Properties:
 
 * compatible: should be
-       - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
+       - snps,dw-mshc: for controllers compliant with synopsys dw-mshc.
 * #address-cells: should be 1.
 * #size-cells: should be 0.
 
index df204e18e030181a23dceebb0bff9de64a84d0a3..6a2a1160a70defdbac92be8850152f1c4448cbde 100644 (file)
@@ -9,12 +9,15 @@ compulsory and any optional properties, common to all SD/MMC drivers, as
 described in mmc.txt, can be used. Additionally the following tmio_mmc-specific
 optional bindings can be used.
 
+Required properties:
+- compatible:  "renesas,sdhi-shmobile" - a generic sh-mobile SDHI unit
+               "renesas,sdhi-sh7372" - SDHI IP on SH7372 SoC
+               "renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
+               "renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
+               "renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
+               "renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
+               "renesas,sdhi-r8a7779" - SDHI IP on R8A7779 SoC
+               "renesas,sdhi-r8a7790" - SDHI IP on R8A7790 SoC
+
 Optional properties:
 - toshiba,mmc-wrprotect-disable: write-protect detection is unavailable
-
-When used with Renesas SDHI hardware, the following compatibility strings
-configure various model-specific properties:
-
-"renesas,sh7372-sdhi": (default) compatible with SH7372
-"renesas,r8a7740-sdhi":        compatible with R8A7740: certain MMC/SD commands have to
-                       wait for the interface to become idle.
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.
 
index 2c6be0377f55d0963970972c4d2b494e73f4507f..d2ea4605d0789dc8d11ff3e1fd8686a30431a43b 100644 (file)
@@ -86,6 +86,7 @@ General Properties:
 
 Clock Properties:
 
+  - fsl,cksel        Timer reference clock source.
   - fsl,tclk-period  Timer reference clock period in nanoseconds.
   - fsl,tmr-prsc     Prescaler, divides the output clock.
   - fsl,tmr-add      Frequency compensation value.
@@ -97,7 +98,7 @@ Clock Properties:
   clock. You must choose these carefully for the clock to work right.
   Here is how to figure good values:
 
-  TimerOsc     = system clock               MHz
+  TimerOsc     = selected reference clock   MHz
   tclk_period  = desired clock period       nanoseconds
   NominalFreq  = 1000 / tclk_period         MHz
   FreqDivRatio = TimerOsc / NominalFreq     (must be greater that 1.0)
@@ -114,6 +115,20 @@ Clock Properties:
   Pulse Per Second (PPS) signal, since this will be offered to the PPS
   subsystem to synchronize the Linux clock.
 
+  Reference clock source is determined by the value, which is holded
+  in CKSEL bits in TMR_CTRL register. "fsl,cksel" property keeps the
+  value, which will be directly written in those bits, that is why,
+  according to reference manual, the next clock sources can be used:
+
+  <0> - external high precision timer reference clock (TSEC_TMR_CLK
+        input is used for this purpose);
+  <1> - eTSEC system clock;
+  <2> - eTSEC1 transmit clock;
+  <3> - RTC clock input.
+
+  When this attribute is not used, eTSEC system clock will serve as
+  IEEE 1588 timer reference clock.
+
 Example:
 
        ptp_clock@24E00 {
@@ -121,6 +136,7 @@ Example:
                reg = <0x24E00 0xB0>;
                interrupts = <12 0x8 13 0x8>;
                interrupt-parent = < &ipic >;
+               fsl,cksel       = <1>;
                fsl,tclk-period = <10>;
                fsl,tmr-prsc    = <100>;
                fsl,tmr-add     = <0x999999A4>;
index eabcb4b5db6e6711b244ea9a35e7b4ff711c12ef..e216af356847c05ac4ab9f2e9a6ae887b1939f2a 100644 (file)
@@ -1,4 +1,4 @@
-* Synopsis Designware PCIe interface
+* Synopsys Designware PCIe interface
 
 Required properties:
 - compatible: should contain "snps,dw-pcie" to identify the
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 b571560ed5f956f05da7edf425b2c3529023cda1..2956800f0240c8b3e48c9427151220ef2fc39fc1 100644 (file)
@@ -38,6 +38,7 @@ linux Linux-specific binding
 lsi    LSI Corp. (LSI Logic)
 marvell        Marvell Technology Group Ltd.
 maxim  Maxim Integrated Products
+microchip      Microchip Technology Inc.
 mosaixtech     Mosaix Technologies, Inc.
 national       National Semiconductor
 nintendo       Nintendo
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
similarity index 99%
rename from fs/cifs/AUTHORS
rename to Documentation/filesystems/cifs/AUTHORS
index ea940b1db77bdb1330b4efc795ad08b023e9acd2..ca4a67a0bb1eb9d8deaa25717fd5b5ac77e5c2c7 100644 (file)
@@ -39,6 +39,7 @@ Shaggy (Dave Kleikamp) for innumerable small fs suggestions and some good cleanu
 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
 -------------------------------------
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 90387c3540f70e4cb99e2401b2f608672f51ffc3..f4021a285460353ca0e4a2eda7b934d7839b57ff 100644 (file)
@@ -17,7 +17,7 @@ Credits:
     Philip Edelbrock <phil@netroedge.com>,
     and Mark Studebaker <mdsxyz123@yahoo.com>
   w83792d.c:
-    Chunhao Huang <DZShen@Winbond.com.tw>,
+    Shane Huang (Winbond),
     Rudolf Marek <r.marek@assembler.cz>
 
 Additional contributors:
index 8a023ce0b72e7726bf8888b88d304f0be5ce51a3..53f7b6866fec4d51c4049ba6c700d58e1950a046 100644 (file)
@@ -7,8 +7,7 @@ Supported chips:
     Addresses scanned: I2C 0x2c - 0x2f
     Datasheet: http://www.winbond.com.tw
 
-Author: Chunhao Huang
-Contact: DZShen <DZShen@Winbond.com.tw>
+Author: Shane Huang (Winbond)
 
 
 Module Parameters
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..fcbb736d55feb439c1152be71355d5ab79f8edd2 100644 (file)
@@ -480,6 +480,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Format: <io>,<irq>,<mode>
                        See header of drivers/net/hamradio/baycom_ser_hdx.c.
 
+       blkdevparts=    Manual partition parsing of block device(s) for
+                       embedded devices based on command line input.
+                       See Documentation/block/cmdline-partition.txt
+
        boot_delay=     Milliseconds to delay each printk during boot.
                        Values larger than 10 seconds (10000) are changed to
                        no delay (0).
@@ -1357,7 +1361,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        pages. In the event, a node is too small to have both
                        kernelcore and Movable pages, kernelcore pages will
                        take priority and other nodes will have a larger number
-                       of kernelcore pages.  The Movable zone is used for the
+                       of Movable pages.  The Movable zone is used for the
                        allocation of pages that may be reclaimed or moved
                        by the page migration subsystem.  This means that
                        HugeTLB pages may not be allocated from this zone.
@@ -1898,6 +1902,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
@@ -3473,6 +3489,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                                the unplug protocol
                        never -- do not unplug even if version check succeeds
 
+       xen_nopvspin    [X86,XEN]
+                       Disables the ticketlock slowpath using Xen PV
+                       optimizations.
+
        xirc2ps_cs=     [NET,PCMCIA]
                        Format:
                        <irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]]
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 a46ddb85e83a0dcdf0f2a54fd9b745eadb31cb6f..85c362d8ea349350947a8363d36dbe7e622ea536 100644 (file)
@@ -28,6 +28,7 @@ ALC269/270/275/276/28x/29x
   alc269-dmic          Enable ALC269(VA) digital mic workaround
   alc271-dmic          Enable ALC271X digital mic workaround
   inv-dmic             Inverted internal mic workaround
+  headset-mic          Indicates a combined headset (headphone+mic) jack
   lenovo-dock          Enables docking station I/O for some Lenovos
   dell-headset-multi   Headset jack, which can also be used as mic-in
   dell-headset-dock    Headset jack (without mic-in), and also dock I/O
@@ -296,6 +297,12 @@ Cirrus Logic CS4206/4207
   imac27       IMac 27 Inch
   auto         BIOS setup (default)
 
+Cirrus Logic CS4208
+===================
+  mba6         MacBook Air 6,1 and 6,2
+  gpio0                Enable GPIO 0 amp
+  auto         BIOS setup (default)
+
 VIA VT17xx/VT18xx/VT20xx
 ========================
   auto         BIOS setup (default)
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 10533173e1538e5f590d318c5d1367904ba2d7c4..a7c34ef3509d5f199511e0547ddba1e88b9a3be9 100644 (file)
@@ -237,11 +237,11 @@ F:        drivers/platform/x86/acer-wmi.c
 
 ACPI
 M:     Len Brown <lenb@kernel.org>
-M:     Rafael J. Wysocki <rjw@sisk.pl>
+M:     Rafael J. Wysocki <rjw@rjwysocki.net>
 L:     linux-acpi@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
-Q:     http://patchwork.kernel.org/project/linux-acpi/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux
+W:     https://01.org/linux-acpi
+Q:     https://patchwork.kernel.org/project/linux-acpi/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
 S:     Supported
 F:     drivers/acpi/
 F:     drivers/pnp/pnpacpi/
@@ -256,21 +256,21 @@ F:        drivers/pci/*/*/*acpi*
 ACPI FAN DRIVER
 M:     Zhang Rui <rui.zhang@intel.com>
 L:     linux-acpi@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
+W:     https://01.org/linux-acpi
 S:     Supported
 F:     drivers/acpi/fan.c
 
 ACPI THERMAL DRIVER
 M:     Zhang Rui <rui.zhang@intel.com>
 L:     linux-acpi@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
+W:     https://01.org/linux-acpi
 S:     Supported
 F:     drivers/acpi/*thermal*
 
 ACPI VIDEO DRIVER
 M:     Zhang Rui <rui.zhang@intel.com>
 L:     linux-acpi@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
+W:     https://01.org/linux-acpi
 S:     Supported
 F:     drivers/acpi/video.c
 
@@ -824,15 +824,21 @@ S:        Maintained
 F:     arch/arm/mach-gemini/
 
 ARM/CSR SIRFPRIMA2 MACHINE SUPPORT
-M:     Barry Song <baohua.song@csr.com>
+M:     Barry Song <baohua@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/baohua/linux.git
 S:     Maintained
 F:     arch/arm/mach-prima2/
+F:     drivers/clk/clk-prima2.c
+F:     drivers/clocksource/timer-prima2.c
+F:     drivers/clocksource/timer-marco.c
 F:     drivers/dma/sirf-dma.c
 F:     drivers/i2c/busses/i2c-sirf.c
+F:     drivers/input/misc/sirfsoc-onkey.c
+F:     drivers/irqchip/irq-sirfsoc.c
 F:     drivers/mmc/host/sdhci-sirf.c
 F:     drivers/pinctrl/sirf/
+F:     drivers/rtc/rtc-sirfsoc.c
 F:     drivers/spi/spi-sirf.c
 
 ARM/EBSA110 MACHINE SUPPORT
@@ -933,24 +939,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 +981,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 +1034,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 +1054,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 +1075,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 +1161,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 +1183,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>
@@ -1320,13 +1322,12 @@ L:      linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-vt8500/
 F:     drivers/clocksource/vt8500_timer.c
-F:     drivers/gpio/gpio-vt8500.c
 F:     drivers/i2c/busses/i2c-wmt.c
 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*
@@ -1387,7 +1388,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
@@ -1816,6 +1817,18 @@ L:       netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/broadcom/bnx2x/
 
+BROADCOM BCM281XX/BCM11XXX ARM ARCHITECTURE
+M:     Christian Daudt <bcm@fixthebug.org>
+L:     bcm-kernel-feedback-list@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)
@@ -2036,10 +2049,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
@@ -2287,7 +2300,7 @@ S:        Maintained
 F:     drivers/net/ethernet/ti/cpmac.c
 
 CPU FREQUENCY DRIVERS
-M:     Rafael J. Wysocki <rjw@sisk.pl>
+M:     Rafael J. Wysocki <rjw@rjwysocki.net>
 M:     Viresh Kumar <viresh.kumar@linaro.org>
 L:     cpufreq@vger.kernel.org
 L:     linux-pm@vger.kernel.org
@@ -2308,8 +2321,17 @@ 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:     Rafael J. Wysocki <rjw@rjwysocki.net>
 M:     Daniel Lezcano <daniel.lezcano@linaro.org>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
@@ -2327,7 +2349,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>
@@ -2494,9 +2516,9 @@ S:        Maintained
 F:     drivers/media/common/cypress_firmware*
 
 CYTTSP TOUCHSCREEN DRIVER
-M:     Javier Martinez Canillas <javier@dowhile0.org>
+M:     Ferruh Yigit <fery@cypress.com>
 L:     linux-input@vger.kernel.org
-S:     Maintained
+S:     Supported
 F:     drivers/input/touchscreen/cyttsp*
 F:     include/linux/input/cyttsp.h
 
@@ -2624,6 +2646,18 @@ F:       include/linux/device-mapper.h
 F:     include/linux/dm-*.h
 F:     include/uapi/linux/dm-*.h
 
+DIGI NEO AND CLASSIC PCI PRODUCTS
+M:     Lidza Louina <lidza.louina@gmail.com>
+L:     driverdev-devel@linuxdriverproject.org
+S:     Maintained
+F:     drivers/staging/dgnc/
+
+DIGI EPCA PCI PRODUCTS
+M:     Lidza Louina <lidza.louina@gmail.com>
+L:     driverdev-devel@linuxdriverproject.org
+S:     Maintained
+F:     drivers/staging/dgap/
+
 DIOLAN U2C-12 I2C DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     linux-i2c@vger.kernel.org
@@ -2683,7 +2717,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*
@@ -2765,7 +2799,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*
 
@@ -2777,7 +2811,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*
 
@@ -3030,7 +3064,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>
@@ -3519,7 +3553,7 @@ F:        fs/freevxfs/
 
 FREEZER
 M:     Pavel Machek <pavel@ucw.cz>
-M:     "Rafael J. Wysocki" <rjw@sisk.pl>
+M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     Documentation/power/freezing-of-tasks.txt
@@ -3590,6 +3624,12 @@ L:       linux-scsi@vger.kernel.org
 S:     Odd Fixes (e.g., new signatures)
 F:     drivers/scsi/fdomain.*
 
+GCOV BASED KERNEL PROFILING
+M:     Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+S:     Maintained
+F:     kernel/gcov/
+F:     Documentation/gcov.txt
+
 GDT SCSI DISK ARRAY CONTROLLER DRIVER
 M:     Achim Leubner <achim_leubner@adaptec.com>
 L:     linux-scsi@vger.kernel.org
@@ -3636,8 +3676,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>
@@ -3679,7 +3719,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
@@ -3757,7 +3798,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>
@@ -3854,7 +3895,7 @@ F:        drivers/video/hgafb.c
 
 HIBERNATION (aka Software Suspend, aka swsusp)
 M:     Pavel Machek <pavel@ucw.cz>
-M:     "Rafael J. Wysocki" <rjw@sisk.pl>
+M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     arch/x86/power/
@@ -4141,6 +4182,13 @@ W:       http://launchpad.net/ideapad-laptop
 S:     Maintained
 F:     drivers/platform/x86/ideapad-laptop.c
 
+IDEAPAD LAPTOP SLIDEBAR DRIVER
+M:     Andrey Moiseev <o2g.org.ru@gmail.com>
+L:     linux-input@vger.kernel.org
+W:     https://github.com/o2genum/ideapad-slidebar
+S:     Maintained
+F:     drivers/input/misc/ideapad_slidebar.c
+
 IDE/ATAPI DRIVERS
 M:     Borislav Petkov <bp@alien8.de>
 L:     linux-ide@vger.kernel.org
@@ -4297,7 +4345,7 @@ F:        drivers/video/i810/
 INTEL MENLOW THERMAL DRIVER
 M:     Sujith Thomas <sujith.thomas@intel.com>
 L:     platform-driver-x86@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
+W:     https://01.org/linux-acpi
 S:     Supported
 F:     drivers/platform/x86/intel_menlow.c
 
@@ -4308,7 +4356,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*
 
@@ -4321,7 +4369,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
 
@@ -4340,7 +4388,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>
@@ -4365,6 +4413,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
@@ -4433,6 +4482,13 @@ L:       linux-serial@vger.kernel.org
 S:     Maintained
 F:     drivers/tty/serial/ioc3_serial.c
 
+IOMMU DRIVERS
+M:     Joerg Roedel <joro@8bytes.org>
+L:     iommu@lists.linux-foundation.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
+S:     Maintained
+F:     drivers/iommu/
+
 IP MASQUERADING
 M:     Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar>
 S:     Maintained
@@ -4558,7 +4614,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>
@@ -4612,7 +4668,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>
@@ -5436,6 +5492,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/
@@ -5883,6 +5940,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
@@ -5945,15 +6004,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>
@@ -6119,7 +6175,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>
@@ -6410,7 +6466,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*
 
@@ -6571,7 +6627,7 @@ S:        Obsolete
 F:     drivers/net/wireless/prism54/
 
 PROMISE SATA TX2/TX4 CONTROLLER LIBATA DRIVER
-M:     Mikael Pettersson <mikpe@it.uu.se>
+M:     Mikael Pettersson <mikpelinux@gmail.com>
 L:     linux-ide@vger.kernel.org
 S:     Maintained
 F:     drivers/ata/sata_promise.*
@@ -6683,7 +6739,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>
@@ -7136,7 +7192,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>
@@ -7182,10 +7238,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/
@@ -7216,7 +7273,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>
@@ -7233,9 +7290,9 @@ F:        include/linux/sched.h
 F:     include/uapi/linux/sched.h
 
 SCORE ARCHITECTURE
-M:     Chen Liqin <liqin.chen@sunplusct.com>
+M:     Chen Liqin <liqin.linux@gmail.com>
 M:     Lennox Wu <lennox.wu@gmail.com>
-W:     http://www.sunplusct.com
+W:     http://www.sunplus.com
 S:     Supported
 F:     arch/score/
 
@@ -7477,7 +7534,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>
@@ -7486,9 +7543,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>
@@ -7526,9 +7583,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>
@@ -7537,7 +7594,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
@@ -7605,6 +7662,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
@@ -7614,7 +7679,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
@@ -7717,6 +7782,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>
@@ -7793,35 +7863,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>
@@ -8059,7 +8101,7 @@ F:        drivers/sh/
 SUSPEND TO RAM
 M:     Len Brown <len.brown@intel.com>
 M:     Pavel Machek <pavel@ucw.cz>
-M:     "Rafael J. Wysocki" <rjw@sisk.pl>
+M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     Documentation/power/
@@ -8090,7 +8132,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>
@@ -8714,9 +8756,8 @@ F:        Documentation/hid/hiddev.txt
 F:     drivers/hid/usbhid/
 
 USB/IP DRIVERS
-M:     Matt Mooney <mfm@muteddisk.com>
 L:     linux-usb@vger.kernel.org
-S:     Maintained
+S:     Orphan
 F:     drivers/staging/usbip/
 
 USB ISP116X DRIVER
@@ -8780,7 +8821,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>
@@ -9311,7 +9351,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>
@@ -9357,6 +9397,7 @@ F:        arch/arm64/include/asm/xen/
 
 XEN NETWORK BACKEND DRIVER
 M:     Ian Campbell <ian.campbell@citrix.com>
+M:     Wei Liu <wei.liu2@citrix.com>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
 L:     netdev@vger.kernel.org
 S:     Supported
index fe8204be566d3fbd23e847ceddd368df0f37450c..126321d2e6ad6a3c594280ca1102e0b25c7e4dd3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 VERSION = 3
-PATCHLEVEL = 11
+PATCHLEVEL = 12
 SUBLEVEL = 0
-EXTRAVERSION =
-NAME = Linux for Workgroups
+EXTRAVERSION = -rc6
+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 1feb169274fe613cc5f0360c797668bf84497c4b..af2cc6eabcc781c4e8f7ee2067de75844ed5874d 100644 (file)
@@ -286,9 +286,6 @@ config HAVE_PERF_USER_STACK_DUMP
 config HAVE_ARCH_JUMP_LABEL
        bool
 
-config HAVE_ARCH_MUTEX_CPU_RELAX
-       bool
-
 config HAVE_RCU_TABLE_FREE
        bool
 
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 f158197ac5b04432ac6beb37c9175629361c0901..b6a8c2dfbe6e42cd51def893784f0780bc67264e 100644 (file)
@@ -45,7 +45,14 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
 
 static inline void arch_spin_unlock(arch_spinlock_t *lock)
 {
-       lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__;
+       unsigned int tmp = __ARCH_SPIN_LOCK_UNLOCKED__;
+
+       __asm__ __volatile__(
+       "       ex  %0, [%1]            \n"
+       : "+r" (tmp)
+       : "r"(&(lock->slock))
+       : "memory");
+
        smp_mb();
 }
 
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;
index 32420824375b351083da3e8686cc0013f0914871..30c9baffa96f1f3a5cab5d6ec6fe83b9f4e86318 100644 (file)
@@ -43,7 +43,7 @@
  * Because it essentially checks if buffer end is within limit and @len is
  * non-ngeative, which implies that buffer start will be within limit too.
  *
- * The reason for rewriting being, for majorit yof cases, @len is generally
+ * The reason for rewriting being, for majoritof cases, @len is generally
  * compile time constant, causing first sub-expression to be compile time
  * subsumed.
  *
@@ -53,7 +53,7 @@
  *
  */
 #define __user_ok(addr, sz)    (((sz) <= TASK_SIZE) && \
-                                (((addr)+(sz)) <= get_fs()))
+                                ((addr) <= (get_fs() - (sz))))
 #define __access_ok(addr, sz)  (unlikely(__kernel_ok) || \
                                 likely(__user_ok((addr), (sz))))
 
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 333238564b67f1239afde4ab4d584f16d8a48572..5d76706139dd36a246eb545f36fe42c1bf44ee9d 100644 (file)
@@ -102,7 +102,7 @@ static int genregs_set(struct task_struct *target,
        REG_IGNORE_ONE(pad2);
        REG_IN_CHUNK(callee, efa, cregs);       /* callee_regs[r25..r13] */
        REG_IGNORE_ONE(efa);                    /* efa update invalid */
-       REG_IN_ONE(stop_pc, &ptregs->ret);      /* stop_pc: PC update */
+       REG_IGNORE_ONE(stop_pc);                        /* PC updated via @ret */
 
        return ret;
 }
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 ee6ef2f60a280c171e42c072401e9b7c1f79ae0c..7e95e1a86510fee2f2e1511f8bc7b63f8fb48122 100644 (file)
@@ -101,7 +101,6 @@ SYSCALL_DEFINE0(rt_sigreturn)
 {
        struct rt_sigframe __user *sf;
        unsigned int magic;
-       int err;
        struct pt_regs *regs = current_pt_regs();
 
        /* Always make any pending restarted system calls return -EINTR */
@@ -119,15 +118,16 @@ SYSCALL_DEFINE0(rt_sigreturn)
        if (!access_ok(VERIFY_READ, sf, sizeof(*sf)))
                goto badframe;
 
-       err = restore_usr_regs(regs, sf);
-       err |= __get_user(magic, &sf->sigret_magic);
-       if (err)
+       if (__get_user(magic, &sf->sigret_magic))
                goto badframe;
 
        if (unlikely(is_do_ss_needed(magic)))
                if (restore_altstack(&sf->uc.uc_stack))
                        goto badframe;
 
+       if (restore_usr_regs(regs, sf))
+               goto badframe;
+
        /* Don't restart from sigreturn */
        syscall_wont_restart(regs);
 
@@ -190,6 +190,15 @@ setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info,
        if (!sf)
                return 1;
 
+       /*
+        * w/o SA_SIGINFO, struct ucontext is partially populated (only
+        * uc_mcontext/uc_sigmask) for kernel's normal user state preservation
+        * during signal handler execution. This works for SA_SIGINFO as well
+        * although the semantics are now overloaded (the same reg state can be
+        * inspected by userland: but are they allowed to fiddle with it ?
+        */
+       err |= stash_usr_regs(sf, regs, set);
+
        /*
         * SA_SIGINFO requires 3 args to signal handler:
         *  #1: sig-no (common to any handler)
@@ -213,14 +222,6 @@ setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info,
                magic = MAGIC_SIGALTSTK;
        }
 
-       /*
-        * w/o SA_SIGINFO, struct ucontext is partially populated (only
-        * uc_mcontext/uc_sigmask) for kernel's normal user state preservation
-        * during signal handler execution. This works for SA_SIGINFO as well
-        * although the semantics are now overloaded (the same reg state can be
-        * inspected by userland: but are they allowed to fiddle with it ?
-        */
-       err |= stash_usr_regs(sf, regs, set);
        err |= __put_user(magic, &sf->sigret_magic);
        if (err)
                return err;
index 0e51e69cf30d772b646ef8a1d2c5605bf63b929a..3fde7de3ea670351ac69e0f441f35f776ebbb7d8 100644 (file)
@@ -227,12 +227,9 @@ void __attribute__((weak)) arc_local_timer_setup(unsigned int cpu)
 {
        struct clock_event_device *clk = &per_cpu(arc_clockevent_device, cpu);
 
-       clockevents_calc_mult_shift(clk, arc_get_core_freq(), 5);
-
-       clk->max_delta_ns = clockevent_delta2ns(ARC_TIMER_MAX, clk);
        clk->cpumask = cpumask_of(cpu);
-
-       clockevents_register_device(clk);
+       clockevents_config_and_register(clk, arc_get_core_freq(),
+                                       0, ARC_TIMER_MAX);
 
        /*
         * setup the per-cpu timer IRQ handler - for all cpus
index c0f832f595d319d1aa21f05228b01fb946ab5591..7ff5b5c183bb026716295c13f7b123de1d67a96f 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"          \
@@ -233,6 +245,12 @@ int misaligned_fixup(unsigned long address, struct pt_regs *regs,
                regs->status32 &= ~STATUS_DE_MASK;
        } else {
                regs->ret += state.instr_len;
+
+               /* handle zero-overhead-loop */
+               if ((regs->ret == regs->lp_end) && (regs->lp_count)) {
+                       regs->ret = regs->lp_start;
+                       regs->lp_count--;
+               }
        }
 
        return 0;
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..1ad6fb6c094db415ec76a72a28356e75bdfd7d17 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
@@ -2214,8 +2217,7 @@ config NEON
 
 config KERNEL_MODE_NEON
        bool "Support for NEON in kernel mode"
-       default n
-       depends on NEON
+       depends on NEON && AEABI
        help
          Say Y to include support for NEON in kernel mode.
 
index a37a50f575a27af2c95abca5c473d6a60233d8b9..db50b626be9871f7426ee394a9b189d8d504c8a3 100644 (file)
@@ -296,10 +296,15 @@ archprepare:
 # Convert bzImage to zImage
 bzImage: zImage
 
-zImage Image xipImage bootpImage uImage: vmlinux
+BOOT_TARGETS   = zImage Image xipImage bootpImage uImage
+INSTALL_TARGETS        = zinstall uinstall install
+
+PHONY += bzImage $(BOOT_TARGETS) $(INSTALL_TARGETS)
+
+$(BOOT_TARGETS): vmlinux
        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
 
-zinstall uinstall install: vmlinux
+$(INSTALL_TARGETS):
        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
 
 %.dtb: | scripts
index 84aa2caf07ed203fb810220258401a1b51f7cab3..ec2f8065f955c5c31a69888bf261c58ea56ffb6d 100644 (file)
@@ -95,24 +95,24 @@ initrd:
        @test "$(INITRD)" != "" || \
        (echo You must specify INITRD; exit -1)
 
-install: $(obj)/Image
-       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+install:
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \
        $(obj)/Image System.map "$(INSTALL_PATH)"
 
-zinstall: $(obj)/zImage
-       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+zinstall:
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \
        $(obj)/zImage System.map "$(INSTALL_PATH)"
 
-uinstall: $(obj)/uImage
-       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+uinstall:
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \
        $(obj)/uImage System.map "$(INSTALL_PATH)"
 
 zi:
-       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \
        $(obj)/zImage System.map "$(INSTALL_PATH)"
 
 i:
-       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \
        $(obj)/Image System.map "$(INSTALL_PATH)"
 
 subdir-            := bootp compressed dts
index 000cf7628e6e90f49357a25c42a73bf07cc97b67..802720e3e8fd5c72004c14cce0bc572a0355356a 100644 (file)
@@ -41,6 +41,8 @@ dtb-$(CONFIG_ARCH_AT91)       += sama5d33ek.dtb
 dtb-$(CONFIG_ARCH_AT91)        += sama5d34ek.dtb
 dtb-$(CONFIG_ARCH_AT91)        += sama5d35ek.dtb
 
+dtb-$(CONFIG_ARCH_ATLAS6) += atlas6-evb.dtb
+
 dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb
 dtb-$(CONFIG_ARCH_BCM) += bcm11351-brt.dtb \
        bcm28155-ap.dtb
@@ -183,6 +185,7 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
        am335x-evm.dtb \
        am335x-evmsk.dtb \
        am335x-bone.dtb \
+       am335x-boneblack.dtb \
        am3517-evm.dtb \
        am3517_mt_ventoux.dtb \
        am43x-epos-evm.dtb
@@ -198,12 +201,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 +234,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 \
diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi
new file mode 100644 (file)
index 0000000..2f66ded
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.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.
+ */
+
+/ {
+       model = "TI AM335x BeagleBone";
+       compatible = "ti,am335x-bone", "ti,am33xx";
+
+       cpus {
+               cpu@0 {
+                       cpu0-supply = <&dcdc2_reg>;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x80000000 0x10000000>; /* 256 MB */
+       };
+
+       am33xx_pinmux: pinmux@44e10800 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&clkout2_pin>;
+
+               user_leds_s0: user_leds_s0 {
+                       pinctrl-single,pins = <
+                               0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE7)  /* gpmc_a5.gpio1_21 */
+                               0x58 (PIN_OUTPUT_PULLUP | MUX_MODE7)    /* gpmc_a6.gpio1_22 */
+                               0x5c (PIN_OUTPUT_PULLDOWN | MUX_MODE7)  /* gpmc_a7.gpio1_23 */
+                               0x60 (PIN_OUTPUT_PULLUP | MUX_MODE7)    /* gpmc_a8.gpio1_24 */
+                       >;
+               };
+
+               i2c0_pins: pinmux_i2c0_pins {
+                       pinctrl-single,pins = <
+                               0x188 (PIN_INPUT_PULLUP | MUX_MODE0)    /* i2c0_sda.i2c0_sda */
+                               0x18c (PIN_INPUT_PULLUP | MUX_MODE0)    /* i2c0_scl.i2c0_scl */
+                       >;
+               };
+
+               uart0_pins: pinmux_uart0_pins {
+                       pinctrl-single,pins = <
+                               0x170 (PIN_INPUT_PULLUP | MUX_MODE0)    /* uart0_rxd.uart0_rxd */
+                               0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+                       >;
+               };
+
+               clkout2_pin: pinmux_clkout2_pin {
+                       pinctrl-single,pins = <
+                               0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
+                       >;
+               };
+
+               cpsw_default: cpsw_default {
+                       pinctrl-single,pins = <
+                               /* Slave 1 */
+                               0x110 (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxerr.mii1_rxerr */
+                               0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txen.mii1_txen */
+                               0x118 (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxdv.mii1_rxdv */
+                               0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd3.mii1_txd3 */
+                               0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd2.mii1_txd2 */
+                               0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd1.mii1_txd1 */
+                               0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd0.mii1_txd0 */
+                               0x12c (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_txclk.mii1_txclk */
+                               0x130 (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxclk.mii1_rxclk */
+                               0x134 (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxd3.mii1_rxd3 */
+                               0x138 (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxd2.mii1_rxd2 */
+                               0x13c (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxd1.mii1_rxd1 */
+                               0x140 (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxd0.mii1_rxd0 */
+                       >;
+               };
+
+               cpsw_sleep: cpsw_sleep {
+                       pinctrl-single,pins = <
+                               /* Slave 1 reset value */
+                               0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       >;
+               };
+
+               davinci_mdio_default: davinci_mdio_default {
+                       pinctrl-single,pins = <
+                               /* MDIO */
+                               0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)    /* mdio_data.mdio_data */
+                               0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0)                   /* mdio_clk.mdio_clk */
+                       >;
+               };
+
+               davinci_mdio_sleep: davinci_mdio_sleep {
+                       pinctrl-single,pins = <
+                               /* MDIO reset value */
+                               0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                               0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       >;
+               };
+       };
+
+       ocp {
+               uart0: serial@44e09000 {
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&uart0_pins>;
+
+                       status = "okay";
+               };
+
+               musb: usb@47400000 {
+                       status = "okay";
+
+                       control@44e10000 {
+                               status = "okay";
+                       };
+
+                       usb-phy@47401300 {
+                               status = "okay";
+                       };
+
+                       usb-phy@47401b00 {
+                               status = "okay";
+                       };
+
+                       usb@47401000 {
+                               status = "okay";
+                       };
+
+                       usb@47401800 {
+                               status = "okay";
+                               dr_mode = "host";
+                       };
+
+                       dma-controller@07402000  {
+                               status = "okay";
+                       };
+               };
+
+               i2c0: i2c@44e0b000 {
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&i2c0_pins>;
+
+                       status = "okay";
+                       clock-frequency = <400000>;
+
+                       tps: tps@24 {
+                               reg = <0x24>;
+                       };
+
+               };
+       };
+
+       leds {
+               pinctrl-names = "default";
+               pinctrl-0 = <&user_leds_s0>;
+
+               compatible = "gpio-leds";
+
+               led@2 {
+                       label = "beaglebone:green:heartbeat";
+                       gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+                       default-state = "off";
+               };
+
+               led@3 {
+                       label = "beaglebone:green:mmc0";
+                       gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "mmc0";
+                       default-state = "off";
+               };
+
+               led@4 {
+                       label = "beaglebone:green:usr2";
+                       gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
+                       default-state = "off";
+               };
+
+               led@5 {
+                       label = "beaglebone:green:usr3";
+                       gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;
+                       default-state = "off";
+               };
+       };
+};
+
+/include/ "tps65217.dtsi"
+
+&tps {
+       regulators {
+               dcdc1_reg: regulator@0 {
+                       regulator-always-on;
+               };
+
+               dcdc2_reg: regulator@1 {
+                       /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
+                       regulator-name = "vdd_mpu";
+                       regulator-min-microvolt = <925000>;
+                       regulator-max-microvolt = <1325000>;
+                       regulator-boot-on;
+                       regulator-always-on;
+               };
+
+               dcdc3_reg: regulator@2 {
+                       /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
+                       regulator-name = "vdd_core";
+                       regulator-min-microvolt = <925000>;
+                       regulator-max-microvolt = <1150000>;
+                       regulator-boot-on;
+                       regulator-always-on;
+               };
+
+               ldo1_reg: regulator@3 {
+                       regulator-always-on;
+               };
+
+               ldo2_reg: regulator@4 {
+                       regulator-always-on;
+               };
+
+               ldo3_reg: regulator@5 {
+                       regulator-always-on;
+               };
+
+               ldo4_reg: regulator@6 {
+                       regulator-always-on;
+               };
+       };
+};
+
+&cpsw_emac0 {
+       phy_id = <&davinci_mdio>, <0>;
+       phy-mode = "mii";
+};
+
+&cpsw_emac1 {
+       phy_id = <&davinci_mdio>, <1>;
+       phy-mode = "mii";
+};
+
+&mac {
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&cpsw_default>;
+       pinctrl-1 = <&cpsw_sleep>;
+
+};
+
+&davinci_mdio {
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&davinci_mdio_default>;
+       pinctrl-1 = <&davinci_mdio_sleep>;
+};
index d318987d44a1931931f553eaad143c54efc53280..7993c489982c86ab2cf03a85b152f9b7db99ad3f 100644 (file)
@@ -8,258 +8,4 @@
 /dts-v1/;
 
 #include "am33xx.dtsi"
-
-/ {
-       model = "TI AM335x BeagleBone";
-       compatible = "ti,am335x-bone", "ti,am33xx";
-
-       cpus {
-               cpu@0 {
-                       cpu0-supply = <&dcdc2_reg>;
-               };
-       };
-
-       memory {
-               device_type = "memory";
-               reg = <0x80000000 0x10000000>; /* 256 MB */
-       };
-
-       am33xx_pinmux: pinmux@44e10800 {
-               pinctrl-names = "default";
-               pinctrl-0 = <&clkout2_pin>;
-
-               user_leds_s0: user_leds_s0 {
-                       pinctrl-single,pins = <
-                               0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE7)  /* gpmc_a5.gpio1_21 */
-                               0x58 (PIN_OUTPUT_PULLUP | MUX_MODE7)    /* gpmc_a6.gpio1_22 */
-                               0x5c (PIN_OUTPUT_PULLDOWN | MUX_MODE7)  /* gpmc_a7.gpio1_23 */
-                               0x60 (PIN_OUTPUT_PULLUP | MUX_MODE7)    /* gpmc_a8.gpio1_24 */
-                       >;
-               };
-
-               i2c0_pins: pinmux_i2c0_pins {
-                       pinctrl-single,pins = <
-                               0x188 (PIN_INPUT_PULLUP | MUX_MODE0)    /* i2c0_sda.i2c0_sda */
-                               0x18c (PIN_INPUT_PULLUP | MUX_MODE0)    /* i2c0_scl.i2c0_scl */
-                       >;
-               };
-
-               uart0_pins: pinmux_uart0_pins {
-                       pinctrl-single,pins = <
-                               0x170 (PIN_INPUT_PULLUP | MUX_MODE0)    /* uart0_rxd.uart0_rxd */
-                               0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
-                       >;
-               };
-
-               clkout2_pin: pinmux_clkout2_pin {
-                       pinctrl-single,pins = <
-                               0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
-                       >;
-               };
-
-               cpsw_default: cpsw_default {
-                       pinctrl-single,pins = <
-                               /* Slave 1 */
-                               0x110 (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxerr.mii1_rxerr */
-                               0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txen.mii1_txen */
-                               0x118 (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxdv.mii1_rxdv */
-                               0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd3.mii1_txd3 */
-                               0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd2.mii1_txd2 */
-                               0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd1.mii1_txd1 */
-                               0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd0.mii1_txd0 */
-                               0x12c (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_txclk.mii1_txclk */
-                               0x130 (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxclk.mii1_rxclk */
-                               0x134 (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxd3.mii1_rxd3 */
-                               0x138 (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxd2.mii1_rxd2 */
-                               0x13c (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxd1.mii1_rxd1 */
-                               0x140 (PIN_INPUT_PULLUP | MUX_MODE0)    /* mii1_rxd0.mii1_rxd0 */
-                       >;
-               };
-
-               cpsw_sleep: cpsw_sleep {
-                       pinctrl-single,pins = <
-                               /* Slave 1 reset value */
-                               0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       >;
-               };
-
-               davinci_mdio_default: davinci_mdio_default {
-                       pinctrl-single,pins = <
-                               /* MDIO */
-                               0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)    /* mdio_data.mdio_data */
-                               0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0)                   /* mdio_clk.mdio_clk */
-                       >;
-               };
-
-               davinci_mdio_sleep: davinci_mdio_sleep {
-                       pinctrl-single,pins = <
-                               /* MDIO reset value */
-                               0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                               0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       >;
-               };
-       };
-
-       ocp {
-               uart0: serial@44e09000 {
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&uart0_pins>;
-
-                       status = "okay";
-               };
-
-               musb: usb@47400000 {
-                       status = "okay";
-
-                       control@44e10000 {
-                               status = "okay";
-                       };
-
-                       usb-phy@47401300 {
-                               status = "okay";
-                       };
-
-                       usb-phy@47401b00 {
-                               status = "okay";
-                       };
-
-                       usb@47401000 {
-                               status = "okay";
-                       };
-
-                       usb@47401800 {
-                               status = "okay";
-                               dr_mode = "host";
-                       };
-
-                       dma-controller@07402000  {
-                               status = "okay";
-                       };
-               };
-
-               i2c0: i2c@44e0b000 {
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&i2c0_pins>;
-
-                       status = "okay";
-                       clock-frequency = <400000>;
-
-                       tps: tps@24 {
-                               reg = <0x24>;
-                       };
-
-               };
-       };
-
-       leds {
-               pinctrl-names = "default";
-               pinctrl-0 = <&user_leds_s0>;
-
-               compatible = "gpio-leds";
-
-               led@2 {
-                       label = "beaglebone:green:heartbeat";
-                       gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
-                       linux,default-trigger = "heartbeat";
-                       default-state = "off";
-               };
-
-               led@3 {
-                       label = "beaglebone:green:mmc0";
-                       gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
-                       linux,default-trigger = "mmc0";
-                       default-state = "off";
-               };
-
-               led@4 {
-                       label = "beaglebone:green:usr2";
-                       gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
-                       default-state = "off";
-               };
-
-               led@5 {
-                       label = "beaglebone:green:usr3";
-                       gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;
-                       default-state = "off";
-               };
-       };
-};
-
-/include/ "tps65217.dtsi"
-
-&tps {
-       regulators {
-               dcdc1_reg: regulator@0 {
-                       regulator-always-on;
-               };
-
-               dcdc2_reg: regulator@1 {
-                       /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
-                       regulator-name = "vdd_mpu";
-                       regulator-min-microvolt = <925000>;
-                       regulator-max-microvolt = <1325000>;
-                       regulator-boot-on;
-                       regulator-always-on;
-               };
-
-               dcdc3_reg: regulator@2 {
-                       /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
-                       regulator-name = "vdd_core";
-                       regulator-min-microvolt = <925000>;
-                       regulator-max-microvolt = <1150000>;
-                       regulator-boot-on;
-                       regulator-always-on;
-               };
-
-               ldo1_reg: regulator@3 {
-                       regulator-always-on;
-               };
-
-               ldo2_reg: regulator@4 {
-                       regulator-always-on;
-               };
-
-               ldo3_reg: regulator@5 {
-                       regulator-always-on;
-               };
-
-               ldo4_reg: regulator@6 {
-                       regulator-always-on;
-               };
-       };
-};
-
-&cpsw_emac0 {
-       phy_id = <&davinci_mdio>, <0>;
-       phy-mode = "mii";
-};
-
-&cpsw_emac1 {
-       phy_id = <&davinci_mdio>, <1>;
-       phy-mode = "mii";
-};
-
-&mac {
-       pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&cpsw_default>;
-       pinctrl-1 = <&cpsw_sleep>;
-
-};
-
-&davinci_mdio {
-       pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&davinci_mdio_default>;
-       pinctrl-1 = <&davinci_mdio_sleep>;
-};
+#include "am335x-bone-common.dtsi"
diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts
new file mode 100644 (file)
index 0000000..197cadf
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am335x-bone-common.dtsi"
+
+&ldo3_reg {
+       regulator-min-microvolt = <1800000>;
+       regulator-max-microvolt = <1800000>;
+       regulator-always-on;
+};
index 05e4485a822521ec1ca234c7991c674f817f4667..8ac2ac1f69cc0d6f50101c815fada7c9183ce9d8 100644 (file)
        };
 
        soc {
+               ranges = <MBUS_ID(0xf0, 0x01) 0 0xd0000000 0x100000
+                         MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+
+               pcie-controller {
+                       status = "okay";
+
+                       /* Connected to Marvell SATA controller */
+                       pcie@1,0 {
+                               /* Port 0, Lane 0 */
+                               status = "okay";
+                       };
+
+                       /* Connected to FL1009 USB 3.0 controller */
+                       pcie@2,0 {
+                               /* Port 1, Lane 0 */
+                               status = "okay";
+                       };
+               };
+
                internal-regs {
                        serial@12000 {
                                clock-frequency = <200000000>;
                                        marvell,pins = "mpp56";
                                        marvell,function = "gpio";
                                };
+
+                               poweroff: poweroff {
+                                       marvell,pins = "mpp8";
+                                       marvell,function = "gpio";
+                               };
                        };
 
                        mdio {
                                        pwm_polarity = <0>;
                                };
                        };
-
-                       pcie-controller {
-                               status = "okay";
-
-                               /* Connected to Marvell SATA controller */
-                               pcie@1,0 {
-                                       /* Port 0, Lane 0 */
-                                       status = "okay";
-                               };
-
-                               /* Connected to FL1009 USB 3.0 controller */
-                               pcie@2,0 {
-                                       /* Port 1, Lane 0 */
-                                       status = "okay";
-                               };
-                       };
                };
        };
 
                button@1 {
                        label = "Power Button";
                        linux,code = <116>;     /* KEY_POWER */
-                       gpios = <&gpio1 30 1>;
+                       gpios = <&gpio1 30 0>;
                };
 
                button@2 {
                };
        };
 
+       gpio_poweroff {
+               compatible = "gpio-poweroff";
+               pinctrl-0 = <&poweroff>;
+               pinctrl-names = "default";
+               gpios = <&gpio0 8 1>;
+       };
+
 };
index def125c0eeaa1596892f5cda162667d99853827c..3058522f5aad2929092f7f7bcc2dd78a9c62c22a 100644 (file)
@@ -70,6 +70,8 @@
 
                        timer@20300 {
                                compatible = "marvell,armada-xp-timer";
+                               clocks = <&coreclk 2>, <&refclk>;
+                               clock-names = "nbclk", "fixed";
                        };
 
                        coreclk: mvebu-sar@18230 {
                        };
                };
        };
+
+       clocks {
+               /* 25 MHz reference crystal */
+               refclk: oscillator {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <25000000>;
+               };
+       };
 };
index cf78ac0b04b12f77a3bc707e0228ce19a9e09785..e74dc15efa9d2f77fa339a16b975f42566ca726e 100644 (file)
                                                         AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE>;  /* PA8 periph A */
                                        };
 
-                                       pinctrl_uart2_rts: uart2_rts-0 {
+                                       pinctrl_usart2_rts: usart2_rts-0 {
                                                atmel,pins =
                                                        <AT91_PIOB 0 AT91_PERIPH_B AT91_PINCTRL_NONE>;  /* PB0 periph B */
                                        };
 
-                                       pinctrl_uart2_cts: uart2_cts-0 {
+                                       pinctrl_usart2_cts: usart2_cts-0 {
                                                atmel,pins =
                                                        <AT91_PIOB 1 AT91_PERIPH_B AT91_PINCTRL_NONE>;  /* PB1 periph B */
                                        };
                                interrupts = <12 IRQ_TYPE_LEVEL_HIGH 0>;
                                dmas = <&dma0 1 AT91_DMA_CFG_PER_ID(0)>;
                                dma-names = "rxtx";
+                               pinctrl-names = "default";
                                #address-cells = <1>;
                                #size-cells = <0>;
                                status = "disabled";
                                interrupts = <26 IRQ_TYPE_LEVEL_HIGH 0>;
                                dmas = <&dma1 1 AT91_DMA_CFG_PER_ID(0)>;
                                dma-names = "rxtx";
+                               pinctrl-names = "default";
                                #address-cells = <1>;
                                #size-cells = <0>;
                                status = "disabled";
index 8678e0c1111981be494cfe6fecf05eb61a393169..6db4f81d4795d2855b83aac5a72cc3c7b8cb6727 100644 (file)
                                interrupts = <17>;
                                fifosize = <128>;
                                clocks = <&clks 13>;
+                               sirf,uart-dma-rx-channel = <21>;
+                               sirf,uart-dma-tx-channel = <2>;
                        };
 
                        uart1: uart@b0060000 {
                                interrupts = <19>;
                                fifosize = <128>;
                                clocks = <&clks 15>;
+                               sirf,uart-dma-rx-channel = <6>;
+                               sirf,uart-dma-tx-channel = <7>;
                        };
 
                        usp0: usp@b0080000 {
                                compatible = "sirf,prima2-usp";
                                reg = <0xb0080000 0x10000>;
                                interrupts = <20>;
+                               fifosize = <128>;
                                clocks = <&clks 28>;
+                               sirf,usp-dma-rx-channel = <17>;
+                               sirf,usp-dma-tx-channel = <18>;
                        };
 
                        usp1: usp@b0090000 {
                                compatible = "sirf,prima2-usp";
                                reg = <0xb0090000 0x10000>;
                                interrupts = <21>;
+                               fifosize = <128>;
                                clocks = <&clks 29>;
+                               sirf,usp-dma-rx-channel = <14>;
+                               sirf,usp-dma-tx-channel = <15>;
                        };
 
                        dmac0: dma-controller@b00b0000 {
                                compatible = "sirf,prima2-vip";
                                reg = <0xb00C0000 0x10000>;
                                clocks = <&clks 31>;
+                               interrupts = <14>;
+                               sirf,vip-dma-rx-channel = <16>;
                        };
 
                        spi0: spi@b00d0000 {
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..bbac42a78ce543c2790a7943697afda1eba2e2aa 100644 (file)
                             <1 14 0xf08>,
                             <1 11 0xf08>,
                             <1 10 0xf08>;
+               /* Unfortunately we need this since some versions of U-Boot
+                * on Exynos don't set the CNTFRQ register, so we need the
+                * value from DT.
+                */
+               clock-frequency = <24000000>;
        };
 
        mct@101C0000 {
                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";
+       };
 };
index c037c223619a7a9ced403c88f1146fb20c112378..b7a1c6d950b984b44efd65c100c05024c80c1b4a 100644 (file)
                                compatible = "fsl,imx27-cspi";
                                reg = <0x1000e000 0x1000>;
                                interrupts = <16>;
-                               clocks = <&clks 53>, <&clks 53>;
+                               clocks = <&clks 53>, <&clks 60>;
                                clock-names = "ipg", "per";
                                status = "disabled";
                        };
                                compatible = "fsl,imx27-cspi";
                                reg = <0x1000f000 0x1000>;
                                interrupts = <15>;
-                               clocks = <&clks 52>, <&clks 52>;
+                               clocks = <&clks 52>, <&clks 60>;
                                clock-names = "ipg", "per";
                                status = "disabled";
                        };
                                compatible = "fsl,imx27-cspi";
                                reg = <0x10017000 0x1000>;
                                interrupts = <6>;
-                               clocks = <&clks 51>, <&clks 51>;
+                               clocks = <&clks 51>, <&clks 60>;
                                clock-names = "ipg", "per";
                                status = "disabled";
                        };
index a85abb424c3482d02dd325ae388bcf63686acc56..54cee6517902d647507f3ed40302135fcba1b849 100644 (file)
                                compatible = "fsl,imx51-pata", "fsl,imx27-pata";
                                reg = <0x83fe0000 0x4000>;
                                interrupts = <70>;
-                               clocks = <&clks 161>;
+                               clocks = <&clks 172>;
                                status = "disabled";
                        };
 
index c0e38a45e4bb487493ed8400328eb27d8a8965b2..9bbe82bdee4112ca0b15de05118b70472b04287c 100644 (file)
 #define MX6QDL_PAD_EIM_D29__ECSPI4_SS0              0x0c8 0x3dc 0x824 0x2 0x1
 #define MX6QDL_PAD_EIM_D29__UART2_RTS_B             0x0c8 0x3dc 0x924 0x4 0x1
 #define MX6QDL_PAD_EIM_D29__UART2_CTS_B             0x0c8 0x3dc 0x000 0x4 0x0
-#define MX6QDL_PAD_EIM_D29__UART2_DTE_RTS_B         0x0c4 0x3dc 0x000 0x4 0x0
-#define MX6QDL_PAD_EIM_D29__UART2_DTE_CTS_B         0x0c4 0x3dc 0x924 0x4 0x1
+#define MX6QDL_PAD_EIM_D29__UART2_DTE_RTS_B         0x0c8 0x3dc 0x000 0x4 0x0
+#define MX6QDL_PAD_EIM_D29__UART2_DTE_CTS_B         0x0c8 0x3dc 0x924 0x4 0x1
 #define MX6QDL_PAD_EIM_D29__GPIO3_IO29              0x0c8 0x3dc 0x000 0x5 0x0
 #define MX6QDL_PAD_EIM_D29__IPU2_CSI1_VSYNC         0x0c8 0x3dc 0x8e4 0x6 0x0
 #define MX6QDL_PAD_EIM_D29__IPU1_DI0_PIN14          0x0c8 0x3dc 0x000 0x7 0x0
index cf7aeaf89e9c1a6b8795113e0726c48b58f16803..1335b2e1bed4c66efe95ee2f679129d3856ccb43 100644 (file)
@@ -13,6 +13,7 @@
                cpu@0 {
                        device_type = "cpu";
                        compatible = "marvell,feroceon";
+                       reg = <0>;
                        clocks = <&core_clk 1>, <&core_clk 3>, <&gate_clk 11>;
                        clock-names = "cpu_clk", "ddrclk", "powersave";
                };
                xor@60900 {
                        compatible = "marvell,orion-xor";
                        reg = <0x60900 0x100
-                              0xd0B00 0x100>;
+                              0x60B00 0x100>;
                        status = "okay";
                        clocks = <&gate_clk 16>;
 
index afdb16417d4e894bc2df369cd7c229a5b7161043..2816bf61267231fd7ec2dd11f87c6da9ed4b3311 100644 (file)
@@ -11,7 +11,7 @@
 
 / {
        model = "TI OMAP3 BeagleBoard xM";
-       compatible = "ti,omap3-beagle-xm, ti,omap3-beagle", "ti,omap3";
+       compatible = "ti,omap3-beagle-xm", "ti,omap36xx", "ti,omap3";
 
        cpus {
                cpu@0 {
index bc48b114eae6404cf0e12ff08113f0bfd6002cf5..2326d11462a57dcb9e43991b359f63ce14da1520 100644 (file)
                >;
        };
 
+       mcbsp2_pins: pinmux_mcbsp2_pins {
+               pinctrl-single,pins = <
+                       0x10c (PIN_INPUT | MUX_MODE0)           /* mcbsp2_fsx.mcbsp2_fsx */
+                       0x10e (PIN_INPUT | MUX_MODE0)           /* mcbsp2_clkx.mcbsp2_clkx */
+                       0x110 (PIN_INPUT | MUX_MODE0)           /* mcbsp2_dr.mcbsp2.dr */
+                       0x112 (PIN_OUTPUT | MUX_MODE0)          /* mcbsp2_dx.mcbsp2_dx */
+               >;
+       };
+
        mmc1_pins: pinmux_mmc1_pins {
                pinctrl-single,pins = <
                        0x114 (PIN_INPUT_PULLUP | MUX_MODE0)    /* sdmmc1_clk.sdmmc1_clk */
        clock-frequency = <400000>;
 };
 
+&mcbsp2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcbsp2_pins>;
+};
+
 &mmc1 {
       pinctrl-names = "default";
       pinctrl-0 = <&mmc1_pins>;
index 7d95cda1fae4f0349bdfb582de99be2baf36dbf6..b41bd57f43287a048b73bfefe35b262ee139600e 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <0>;
                        pinctrl-single,register-width = <16>;
-                       pinctrl-single,function-mask = <0x7f1f>;
+                       pinctrl-single,function-mask = <0xff1f>;
                };
 
                omap3_pmx_wkup: pinmux@0x48002a00 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        pinctrl-single,register-width = <16>;
-                       pinctrl-single,function-mask = <0x7f1f>;
+                       pinctrl-single,function-mask = <0xff1f>;
                };
 
                gpio1: gpio@48310000 {
index faa95b5b242ee437aeea84c8d4dde915a67c2031..814ab67c8c299b0b818f669c917d51ebcb8a94c0 100644 (file)
         */
                clock-frequency = <19200000>;
        };
+
+       /* regulator for wl12xx on sdio5 */
+       wl12xx_vmmc: wl12xx_vmmc {
+               pinctrl-names = "default";
+               pinctrl-0 = <&wl12xx_gpio>;
+               compatible = "regulator-fixed";
+               regulator-name = "vwl1271";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               gpio = <&gpio2 11 0>;
+               startup-delay-us = <70000>;
+               enable-active-high;
+       };
 };
 
 &omap4_pmx_wkup {
                        0x1c (PIN_OUTPUT | MUX_MODE3)   /* gpio_wk8 */
                >;
        };
+
+       /*
+        * wl12xx GPIO outputs for WLAN_EN, BT_EN, FM_EN, BT_WAKEUP
+        * REVISIT: Are the pull-ups needed for GPIO 48 and 49?
+        */
+       wl12xx_gpio: pinmux_wl12xx_gpio {
+               pinctrl-single,pins = <
+                       0x26 (PIN_OUTPUT | MUX_MODE3)           /* gpmc_a19.gpio_43 */
+                       0x2c (PIN_OUTPUT | MUX_MODE3)           /* gpmc_a22.gpio_46 */
+                       0x30 (PIN_OUTPUT_PULLUP | MUX_MODE3)    /* gpmc_a24.gpio_48 */
+                       0x32 (PIN_OUTPUT_PULLUP | MUX_MODE3)    /* gpmc_a25.gpio_49 */
+               >;
+       };
+
+       /* wl12xx GPIO inputs and SDIO pins */
+       wl12xx_pins: pinmux_wl12xx_pins {
+               pinctrl-single,pins = <
+                       0x38 (PIN_INPUT | MUX_MODE3)            /* gpmc_ncs2.gpio_52 */
+                       0x3a (PIN_INPUT | MUX_MODE3)            /* gpmc_ncs3.gpio_53 */
+                       0x108 (PIN_OUTPUT | MUX_MODE0)          /* sdmmc5_clk.sdmmc5_clk */
+                       0x10a (PIN_INPUT_PULLUP | MUX_MODE0)    /* sdmmc5_cmd.sdmmc5_cmd */
+                       0x10c (PIN_INPUT_PULLUP | MUX_MODE0)    /* sdmmc5_dat0.sdmmc5_dat0 */
+                       0x10e (PIN_INPUT_PULLUP | MUX_MODE0)    /* sdmmc5_dat1.sdmmc5_dat1 */
+                       0x110 (PIN_INPUT_PULLUP | MUX_MODE0)    /* sdmmc5_dat2.sdmmc5_dat2 */
+                       0x112 (PIN_INPUT_PULLUP | MUX_MODE0)    /* sdmmc5_dat3.sdmmc5_dat3 */
+               >;
+       };
 };
 
 &i2c1 {
 };
 
 &mmc5 {
-       ti,non-removable;
+       pinctrl-names = "default";
+       pinctrl-0 = <&wl12xx_pins>;
+       vmmc-supply = <&wl12xx_vmmc>;
+       non-removable;
        bus-width = <4>;
+       cap-power-off-card;
 };
 
 &emif1 {
index 7951b4ea500af37ac2a4f6b8f59e97cbf263d595..4f78380ecdb890c5b72cae0ac8937365540d80bd 100644 (file)
                        "DMic", "Digital Mic",
                        "Digital Mic", "Digital Mic1 Bias";
        };
+
+       /* regulator for wl12xx on sdio5 */
+       wl12xx_vmmc: wl12xx_vmmc {
+               pinctrl-names = "default";
+               pinctrl-0 = <&wl12xx_gpio>;
+               compatible = "regulator-fixed";
+               regulator-name = "vwl1271";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               gpio = <&gpio2 22 0>;
+               startup-delay-us = <70000>;
+               enable-active-high;
+       };
 };
 
 &omap4_pmx_wkup {
                        0xf0 (PIN_INPUT_PULLUP | MUX_MODE0)     /* i2c4_sda */
                >;
        };
+
+       /* wl12xx GPIO output for WLAN_EN */
+       wl12xx_gpio: pinmux_wl12xx_gpio {
+               pinctrl-single,pins = <
+                       0x3c (PIN_OUTPUT | MUX_MODE3)           /* gpmc_nwp.gpio_54 */
+               >;
+       };
+
+       /* wl12xx GPIO inputs and SDIO pins */
+       wl12xx_pins: pinmux_wl12xx_pins {
+               pinctrl-single,pins = <
+                       0x3a (PIN_INPUT | MUX_MODE3)            /* gpmc_ncs3.gpio_53 */
+                       0x108 (PIN_OUTPUT | MUX_MODE3)          /* sdmmc5_clk.sdmmc5_clk */
+                       0x10a (PIN_INPUT_PULLUP | MUX_MODE3)    /* sdmmc5_cmd.sdmmc5_cmd */
+                       0x10c (PIN_INPUT_PULLUP | MUX_MODE3)    /* sdmmc5_dat0.sdmmc5_dat0 */
+                       0x10e (PIN_INPUT_PULLUP | MUX_MODE3)    /* sdmmc5_dat1.sdmmc5_dat1 */
+                       0x110 (PIN_INPUT_PULLUP | MUX_MODE3)    /* sdmmc5_dat2.sdmmc5_dat2 */
+                       0x112 (PIN_INPUT_PULLUP | MUX_MODE3)    /* sdmmc5_dat3.sdmmc5_dat3 */
+               >;
+       };
 };
 
 &i2c1 {
 };
 
 &mmc5 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&wl12xx_pins>;
+       vmmc-supply = <&wl12xx_vmmc>;
+       non-removable;
        bus-width = <4>;
-       ti,non-removable;
+       cap-power-off-card;
 };
 
 &emif1 {
index 07be2cd7b3188f6c943b1928e812dfa676973bfb..7cdea1bfea091917455e46cc18af7d6d80a2c0f0 100644 (file)
                omap_dwc3@4a020000 {
                        compatible = "ti,dwc3";
                        ti,hwmods = "usb_otg_ss";
-                       reg = <0x4a020000 0x1000>;
+                       reg = <0x4a020000 0x10000>;
                        interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
                        #address-cells = <1>;
                        #size-cells = <1>;
                        ranges;
                        dwc3@4a030000 {
                                compatible = "snps,dwc3";
-                               reg = <0x4a030000 0x1000>;
+                               reg = <0x4a030000 0x10000>;
                                interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
                                usb-phy = <&usb2_phy>, <&usb3_phy>;
                                tx-fifo-resize;
                        };
                };
 
-               ocp2scp {
+               ocp2scp@4a080000 {
                        compatible = "ti,omap-ocp2scp";
                        #address-cells = <1>;
                        #size-cells = <1>;
+                       reg = <0x4a080000 0x20>;
                        ranges;
                        ti,hwmods = "ocp2scp1";
                        usb2_phy: usb2phy@4a084000 {
index bbeb623fc2c6f82dc9f92b1c77a90811946f9736..27ed9f5144bcb927d777cf4468c1ddaa5c11c837 100644 (file)
                        compatible = "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       ranges = <0xb0000000 0xb0000000 0x180000>;
+                       ranges = <0xb0000000 0xb0000000 0x180000>,
+                              <0x56000000 0x56000000 0x1b00000>;
 
                        timer@b0020000 {
                                compatible = "sirf,prima2-tick";
                        uart0: uart@b0050000 {
                                cell-index = <0>;
                                compatible = "sirf,prima2-uart";
-                               reg = <0xb0050000 0x10000>;
+                               reg = <0xb0050000 0x1000>;
                                interrupts = <17>;
+                               fifosize = <128>;
                                clocks = <&clks 13>;
+                               sirf,uart-dma-rx-channel = <21>;
+                               sirf,uart-dma-tx-channel = <2>;
                        };
 
                        uart1: uart@b0060000 {
                                cell-index = <1>;
                                compatible = "sirf,prima2-uart";
-                               reg = <0xb0060000 0x10000>;
+                               reg = <0xb0060000 0x1000>;
                                interrupts = <18>;
+                               fifosize = <32>;
                                clocks = <&clks 14>;
                        };
 
                        uart2: uart@b0070000 {
                                cell-index = <2>;
                                compatible = "sirf,prima2-uart";
-                               reg = <0xb0070000 0x10000>;
+                               reg = <0xb0070000 0x1000>;
                                interrupts = <19>;
+                               fifosize = <128>;
                                clocks = <&clks 15>;
+                               sirf,uart-dma-rx-channel = <6>;
+                               sirf,uart-dma-tx-channel = <7>;
                        };
 
                        usp0: usp@b0080000 {
                                compatible = "sirf,prima2-usp";
                                reg = <0xb0080000 0x10000>;
                                interrupts = <20>;
+                               fifosize = <128>;
                                clocks = <&clks 28>;
+                               sirf,usp-dma-rx-channel = <17>;
+                               sirf,usp-dma-tx-channel = <18>;
                        };
 
                        usp1: usp@b0090000 {
                                compatible = "sirf,prima2-usp";
                                reg = <0xb0090000 0x10000>;
                                interrupts = <21>;
+                               fifosize = <128>;
                                clocks = <&clks 29>;
+                               sirf,usp-dma-rx-channel = <14>;
+                               sirf,usp-dma-tx-channel = <15>;
                        };
 
                        usp2: usp@b00a0000 {
                                compatible = "sirf,prima2-usp";
                                reg = <0xb00a0000 0x10000>;
                                interrupts = <22>;
+                               fifosize = <128>;
                                clocks = <&clks 30>;
+                               sirf,usp-dma-rx-channel = <10>;
+                               sirf,usp-dma-tx-channel = <11>;
                        };
 
                        dmac0: dma-controller@b00b0000 {
                                compatible = "sirf,prima2-vip";
                                reg = <0xb00C0000 0x10000>;
                                clocks = <&clks 31>;
+                               interrupts = <14>;
+                               sirf,vip-dma-rx-channel = <16>;
                        };
 
                        spi0: spi@b00d0000 {
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 6c26caa880f2917344ada23a6a8e8e106412a0f9..658fcc537576b309ae06ecb74eaf65b3e3f2856c 100644 (file)
        };
 
        sdhi0: sdhi@ee100000 {
-               compatible = "renesas,r8a73a4-sdhi";
+               compatible = "renesas,sdhi-r8a73a4";
                reg = <0 0xee100000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 165 4>;
        };
 
        sdhi1: sdhi@ee120000 {
-               compatible = "renesas,r8a73a4-sdhi";
+               compatible = "renesas,sdhi-r8a73a4";
                reg = <0 0xee120000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 166 4>;
        };
 
        sdhi2: sdhi@ee140000 {
-               compatible = "renesas,r8a73a4-sdhi";
+               compatible = "renesas,sdhi-r8a73a4";
                reg = <0 0xee140000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 167 4>;
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 45ac404ab6d8b79b246f6f5724f3609b48bf58cb..3577aba8258336bab80d44c3065c6e94f6ffe8a7 100644 (file)
@@ -96,6 +96,5 @@
        pfc: pfc@fffc0000 {
                compatible = "renesas,pfc-r8a7778";
                reg = <0xfffc000 0x118>;
-               #gpio-range-cells = <3>;
        };
 };
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..ebbe507fcbfa118280da96482dfaa109854f18c8 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";
        pfc: pfc@fffc0000 {
                compatible = "renesas,pfc-r8a7779";
                reg = <0xfffc0000 0x23c>;
-               #gpio-range-cells = <3>;
        };
 
        thermal@ffc48000 {
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 3b879e7c697c336748d5f35adf6744c6d7e14458..413b4c29e782d7ded622563b8a458e28d382db19 100644 (file)
        pfc: pfc@e6060000 {
                compatible = "renesas,pfc-r8a7790";
                reg = <0 0xe6060000 0 0x250>;
-               #gpio-range-cells = <3>;
        };
 
        sdhi0: sdhi@ee100000 {
-               compatible = "renesas,r8a7790-sdhi";
+               compatible = "renesas,sdhi-r8a7790";
                reg = <0 0xee100000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 165 4>;
        };
 
        sdhi1: sdhi@ee120000 {
-               compatible = "renesas,r8a7790-sdhi";
+               compatible = "renesas,sdhi-r8a7790";
                reg = <0 0xee120000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 166 4>;
        };
 
        sdhi2: sdhi@ee140000 {
-               compatible = "renesas,r8a7790-sdhi";
+               compatible = "renesas,sdhi-r8a7790";
                reg = <0 0xee140000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 167 4>;
        };
 
        sdhi3: sdhi@ee160000 {
-               compatible = "renesas,r8a7790-sdhi";
+               compatible = "renesas,sdhi-r8a7790";
                reg = <0 0xee160000 0 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 168 4>;
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..3955c7606a6f45a33036bec612ad918806315dee 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>;
        };
 
        sdhi0: sdhi@ee100000 {
-               compatible = "renesas,r8a7740-sdhi";
+               compatible = "renesas,sdhi-r8a7740";
                reg = <0xee100000 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 83 4
 
        /* SDHI1 and SDHI2 have no CD pins, no need for CD IRQ */
        sdhi1: sdhi@ee120000 {
-               compatible = "renesas,r8a7740-sdhi";
+               compatible = "renesas,sdhi-r8a7740";
                reg = <0xee120000 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 88 4
        };
 
        sdhi2: sdhi@ee140000 {
-               compatible = "renesas,r8a7740-sdhi";
+               compatible = "renesas,sdhi-r8a7740";
                reg = <0xee140000 0x100>;
                interrupt-parent = <&gic>;
                interrupts = <0 104 4
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 06ea7d42ce8e6bb9f72633a14abd2ace113fa712..2a45092a40e3251e44447f3349e80ee0a69e97a4 100644 (file)
 #   $4 - default install path (blank if root directory)
 #
 
+verify () {
+       if [ ! -f "$1" ]; then
+               echo ""                                                   1>&2
+               echo " *** Missing file: $1"                              1>&2
+               echo ' *** You need to run "make" before "make install".' 1>&2
+               echo ""                                                   1>&2
+               exit 1
+       fi
+}
+
+# Make sure the files actually exist
+verify "$2"
+verify "$3"
+
 # User may have a custom install script
 if [ -x ~/bin/${INSTALLKERNEL} ]; then exec ~/bin/${INSTALLKERNEL} "$@"; fi
 if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi
index 39ad030ac0c72b529b9cf3166a003b9feaa1f879..8e1a0245907f85be1a460bfa785f744daf285d6f 100644 (file)
@@ -269,6 +269,11 @@ static const struct edmacc_param dummy_paramset = {
        .ccnt = 1,
 };
 
+static const struct of_device_id edma_of_ids[] = {
+       { .compatible = "ti,edma3", },
+       {}
+};
+
 /*****************************************************************************/
 
 static void map_dmach_queue(unsigned ctlr, unsigned ch_no,
@@ -560,14 +565,38 @@ static int reserve_contiguous_slots(int ctlr, unsigned int id,
 static int prepare_unused_channel_list(struct device *dev, void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       int i, ctlr;
+       int i, count, ctlr;
+       struct of_phandle_args  dma_spec;
+
+       if (dev->of_node) {
+               count = of_property_count_strings(dev->of_node, "dma-names");
+               if (count < 0)
+                       return 0;
+               for (i = 0; i < count; i++) {
+                       if (of_parse_phandle_with_args(dev->of_node, "dmas",
+                                                      "#dma-cells", i,
+                                                      &dma_spec))
+                               continue;
+
+                       if (!of_match_node(edma_of_ids, dma_spec.np)) {
+                               of_node_put(dma_spec.np);
+                               continue;
+                       }
 
+                       clear_bit(EDMA_CHAN_SLOT(dma_spec.args[0]),
+                                 edma_cc[0]->edma_unused);
+                       of_node_put(dma_spec.np);
+               }
+               return 0;
+       }
+
+       /* For non-OF case */
        for (i = 0; i < pdev->num_resources; i++) {
                if ((pdev->resource[i].flags & IORESOURCE_DMA) &&
                                (int)pdev->resource[i].start >= 0) {
                        ctlr = EDMA_CTLR(pdev->resource[i].start);
                        clear_bit(EDMA_CHAN_SLOT(pdev->resource[i].start),
-                                       edma_cc[ctlr]->edma_unused);
+                                 edma_cc[ctlr]->edma_unused);
                }
        }
 
@@ -1235,6 +1264,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
@@ -1745,11 +1791,6 @@ static int edma_probe(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id edma_of_ids[] = {
-       { .compatible = "ti,edma3", },
-       {}
-};
-
 static struct platform_driver edma_driver = {
        .driver = {
                .name   = "edma",
index 370236dd1a03309ee3b123e705aa80132c908427..990250965f2cfb4e4e3a984678fcf62eedbcdb8d 100644 (file)
@@ -51,7 +51,8 @@ void mcpm_cpu_power_down(void)
 {
        phys_reset_t phys_reset;
 
-       BUG_ON(!platform_ops);
+       if (WARN_ON_ONCE(!platform_ops || !platform_ops->power_down))
+               return;
        BUG_ON(!irqs_disabled());
 
        /*
@@ -93,7 +94,8 @@ void mcpm_cpu_suspend(u64 expected_residency)
 {
        phys_reset_t phys_reset;
 
-       BUG_ON(!platform_ops);
+       if (WARN_ON_ONCE(!platform_ops || !platform_ops->suspend))
+               return;
        BUG_ON(!irqs_disabled());
 
        /* Very similar to mcpm_cpu_power_down() */
index d56c932580eb201439c8a63aa401abddd157cbbf..025f6ce38596736eea2c929a211b23fd4eaf0d56 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <asm/mach/sharpsl_param.h>
+#include <asm/memory.h>
 
 /*
  * Certain hardware parameters determined at the time of device manufacture,
  */
 #ifdef CONFIG_ARCH_SA1100
 #define PARAM_BASE     0xe8ffc000
+#define param_start(x) (void *)(x)
 #else
 #define PARAM_BASE     0xa0000a00
+#define param_start(x) __va(x)
 #endif
 #define MAGIC_CHG(a,b,c,d) ( ( d << 24 ) | ( c << 16 )  | ( b << 8 ) | a )
 
@@ -41,7 +44,7 @@ EXPORT_SYMBOL(sharpsl_param);
 
 void sharpsl_save_param(void)
 {
-       memcpy(&sharpsl_param, (void *)PARAM_BASE, sizeof(struct sharpsl_param_info));
+       memcpy(&sharpsl_param, param_start(PARAM_BASE), sizeof(struct sharpsl_param_info));
 
        if (sharpsl_param.comadj_keyword != COMADJ_MAGIC)
                sharpsl_param.comadj=-1;
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 6e572c64cf5a1258008232a002301ab7925b0911..119fc378fc520f8ae5cb9074686570b6436bcd93 100644 (file)
@@ -36,6 +36,7 @@ CONFIG_ARCH_TEGRA_114_SOC=y
 CONFIG_TEGRA_PCI=y
 CONFIG_TEGRA_EMC_SCALING_ENABLE=y
 CONFIG_ARCH_U8500=y
+CONFIG_MACH_HREFV60=y
 CONFIG_MACH_SNOWBALL=y
 CONFIG_MACH_UX500_DT=y
 CONFIG_ARCH_VEXPRESS=y
@@ -46,6 +47,7 @@ CONFIG_ARCH_ZYNQ=y
 CONFIG_SMP=y
 CONFIG_HIGHPTE=y
 CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -133,6 +135,7 @@ CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_ESDHC_IMX=y
 CONFIG_MMC_SDHCI_TEGRA=y
 CONFIG_MMC_SDHCI_SPEAR=y
 CONFIG_MMC_OMAP=y
index 19d6cd6f29f98b95962cca5643dca61debdf7b8e..3a14ea8fe97e5cac183ad8c9148b816e473b4ae5 100644 (file)
@@ -148,7 +148,7 @@ AES_Te:
 @               const AES_KEY *key) {
 .align 5
 ENTRY(AES_encrypt)
-       sub     r3,pc,#8                @ AES_encrypt
+       adr     r3,AES_encrypt
        stmdb   sp!,{r1,r4-r12,lr}
        mov     r12,r0          @ inp
        mov     r11,r2
@@ -381,7 +381,7 @@ _armv4_AES_encrypt:
 .align 5
 ENTRY(private_AES_set_encrypt_key)
 _armv4_AES_set_encrypt_key:
-       sub     r3,pc,#8                @ AES_set_encrypt_key
+       adr     r3,_armv4_AES_set_encrypt_key
        teq     r0,#0
        moveq   r0,#-1
        beq     .Labrt
@@ -843,7 +843,7 @@ AES_Td:
 @               const AES_KEY *key) {
 .align 5
 ENTRY(AES_decrypt)
-       sub     r3,pc,#8                @ AES_decrypt
+       adr     r3,AES_decrypt
        stmdb   sp!,{r1,r4-r12,lr}
        mov     r12,r0          @ inp
        mov     r11,r2
index d3db39860b9cc5eb83053f99f9430b926443609c..59ceae8f3c959616851a21ba3f08ae18941146ca 100644 (file)
@@ -31,5 +31,4 @@ generic-y += termbits.h
 generic-y += termios.h
 generic-y += timex.h
 generic-y += trace_clock.h
-generic-y += types.h
 generic-y += unaligned.h
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 bfc198c759130109d44b73b4506ea853d01fba28..863c892b4aaa7403c3bde97b7de3b2cd9a75519c 100644 (file)
@@ -16,7 +16,7 @@
 
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-       asm goto("1:\n\t"
+       asm_volatile_goto("1:\n\t"
                 JUMP_LABEL_NOP "\n\t"
                 ".pushsection __jump_table,  \"aw\"\n\t"
                 ".word 1b, %l[l_yes], %c0\n\t"
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 0f7b7620e9a554b0b4a0ba4939a60c905e0a435c..fc82a88f5b69e556e9235583364b5149b2572b66 100644 (file)
@@ -76,8 +76,11 @@ int mcpm_cpu_power_up(unsigned int cpu, unsigned int cluster);
  *
  * This must be called with interrupts disabled.
  *
- * This does not return.  Re-entry in the kernel is expected via
- * mcpm_entry_point.
+ * On success this does not return.  Re-entry in the kernel is expected
+ * via mcpm_entry_point.
+ *
+ * This will return if mcpm_platform_register() has not been called
+ * previously in which case the caller should take appropriate action.
  */
 void mcpm_cpu_power_down(void);
 
@@ -98,8 +101,11 @@ void mcpm_cpu_power_down(void);
  *
  * This must be called with interrupts disabled.
  *
- * This does not return.  Re-entry in the kernel is expected via
- * mcpm_entry_point.
+ * On success this does not return.  Re-entry in the kernel is expected
+ * via mcpm_entry_point.
+ *
+ * This will return if mcpm_platform_register() has not been called
+ * previously in which case the caller should take appropriate action.
  */
 void mcpm_cpu_suspend(u64 expected_residency);
 
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 f1d96d4e8092a652aeb84f5825082a8f9064cd20..73ddd7239b33aa77d178ae1341c0c46c736a08e5 100644 (file)
@@ -57,6 +57,9 @@ static inline void syscall_get_arguments(struct task_struct *task,
                                         unsigned int i, unsigned int n,
                                         unsigned long *args)
 {
+       if (n == 0)
+               return;
+
        if (i + n > SYSCALL_MAX_ARGS) {
                unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
                unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
@@ -81,6 +84,9 @@ static inline void syscall_set_arguments(struct task_struct *task,
                                         unsigned int i, unsigned int n,
                                         const unsigned long *args)
 {
+       if (n == 0)
+               return;
+
        if (i + n > SYSCALL_MAX_ARGS) {
                pr_warning("%s called with max args %d, handling only %d\n",
                           __func__, i + n, SYSCALL_MAX_ARGS);
index 7e1f76027f666e252c35bd320d4518e110548c47..72abdc541f38f6e892a24050d1992fc37098f5e3 100644 (file)
 #include <asm/unified.h>
 #include <asm/compiler.h>
 
+#if __LINUX_ARM_ARCH__ < 6
+#include <asm-generic/uaccess-unaligned.h>
+#else
+#define __get_user_unaligned __get_user
+#define __put_user_unaligned __put_user
+#endif
+
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
 
index 74ad15d1a065fba97aac1d4ac43ff33a9e994470..bc6bd9683ba4555d9713e1693b258e6204fc90a5 100644 (file)
@@ -442,10 +442,10 @@ local_restart:
        ldrcc   pc, [tbl, scno, lsl #2]         @ call sys_* routine
 
        add     r1, sp, #S_OFF
-       cmp     scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE)
+2:     cmp     scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE)
        eor     r0, scno, #__NR_SYSCALL_BASE    @ put OS number back
        bcs     arm_syscall
-2:     mov     why, #0                         @ no longer a real syscall
+       mov     why, #0                         @ no longer a real syscall
        b       sys_ni_syscall                  @ not private func
 
 #if defined(CONFIG_OABI_COMPAT) || !defined(CONFIG_AEABI)
index de23a9beed1333d86d1143a7b31613ff7376440d..39f89fbd5111ee9f0a96d6712e1f0f2ba308147d 100644 (file)
 #ifdef CONFIG_CONTEXT_TRACKING
        .if     \save
        stmdb   sp!, {r0-r3, ip, lr}
-       bl      user_exit
+       bl      context_tracking_user_exit
        ldmia   sp!, {r0-r3, ip, lr}
        .else
-       bl      user_exit
+       bl      context_tracking_user_exit
        .endif
 #endif
        .endm
 #ifdef CONFIG_CONTEXT_TRACKING
        .if     \save
        stmdb   sp!, {r0-r3, ip, lr}
-       bl      user_enter
+       bl      context_tracking_user_enter
        ldmia   sp!, {r0-r3, ip, lr}
        .else
-       bl      user_enter
+       bl      context_tracking_user_enter
        .endif
 #endif
        .endm
index 2c7cc1e03473aee9463e86d7dbedfc999f6e51f7..476de57dcef284602e126e29e2da03465df8ff09 100644 (file)
@@ -487,7 +487,26 @@ __fixup_smp:
        mrc     p15, 0, r0, c0, c0, 5   @ read MPIDR
        and     r0, r0, #0xc0000000     @ multiprocessing extensions and
        teq     r0, #0x80000000         @ not part of a uniprocessor system?
-       moveq   pc, lr                  @ yes, assume SMP
+       bne    __fixup_smp_on_up        @ no, assume UP
+
+       @ Core indicates it is SMP. Check for Aegis SOC where a single
+       @ Cortex-A9 CPU is present but SMP operations fault.
+       mov     r4, #0x41000000
+       orr     r4, r4, #0x0000c000
+       orr     r4, r4, #0x00000090
+       teq     r3, r4                  @ Check for ARM Cortex-A9
+       movne   pc, lr                  @ Not ARM Cortex-A9,
+
+       @ If a future SoC *does* use 0x0 as the PERIPH_BASE, then the
+       @ below address check will need to be #ifdef'd or equivalent
+       @ for the Aegis platform.
+       mrc     p15, 4, r0, c15, c0     @ get SCU base address
+       teq     r0, #0x0                @ '0' on actual UP A9 hardware
+       beq     __fixup_smp_on_up       @ So its an A9 UP
+       ldr     r0, [r0, #4]            @ read SCU Config
+       and     r0, r0, #0x3            @ number of CPUs
+       teq     r0, #0x0                @ is 1?
+       movne   pc, lr
 
 __fixup_smp_on_up:
        adr     r0, 1f
index 71e08baee209387f899e14a32fa32e02682b0ae8..c02ba4af599f417113fdb2c260270ae7162575e6 100644 (file)
@@ -58,14 +58,14 @@ static const struct kvm_irq_level a15_vtimer_irq = {
  */
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 {
-       struct kvm_regs *cpu_reset;
+       struct kvm_regs *reset_regs;
        const struct kvm_irq_level *cpu_vtimer_irq;
 
        switch (vcpu->arch.target) {
        case KVM_ARM_TARGET_CORTEX_A15:
                if (vcpu->vcpu_id > a15_max_cpu_idx)
                        return -EINVAL;
-               cpu_reset = &a15_regs_reset;
+               reset_regs = &a15_regs_reset;
                vcpu->arch.midr = read_cpuid_id();
                cpu_vtimer_irq = &a15_vtimer_irq;
                break;
@@ -74,7 +74,7 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
        }
 
        /* Reset core registers */
-       memcpy(&vcpu->arch.regs, cpu_reset, sizeof(vcpu->arch.regs));
+       memcpy(&vcpu->arch.regs, reset_regs, sizeof(vcpu->arch.regs));
 
        /* Reset CP15 registers */
        kvm_reset_coprocs(vcpu);
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 180b3024bec3ab36cc2d7cdb62e92d7b2298d297..f607deb40f4da6a88a0778b203cdcfbbc8518ecc 100644 (file)
@@ -93,7 +93,7 @@ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction at91rm9200_timer_irq = {
        .name           = "at91_tick",
-       .flags          = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .flags          = IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
        .handler        = at91rm9200_timer_interrupt,
        .irq            = NR_IRQS_LEGACY + AT91_ID_SYS,
 };
index 3a4bc2e1a65e73d3b2187f90f6b84a43e7ec6468..bb392320a0dd39d978bd5f1d3e861d2fce14b14c 100644 (file)
@@ -171,7 +171,7 @@ static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)
 
 static struct irqaction at91sam926x_pit_irq = {
        .name           = "at91_tick",
-       .flags          = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .flags          = IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
        .handler        = at91sam926x_pit_interrupt,
        .irq            = NR_IRQS_LEGACY + AT91_ID_SYS,
 };
index 721a1a34dd1d86027161e66b9cfaee7161ebfd03..c40c1e2ef80fa9d1485c06669afad3caf0ea17fc 100644 (file)
 #include "at91_rstc.h"
                        .arm
 
+/*
+ * at91_ramc_base is an array void*
+ * init at NULL if only one DDR controler is present in or DT
+ */
                        .globl  at91sam9g45_restart
 
 at91sam9g45_restart:
                        ldr     r5, =at91_ramc_base             @ preload constants
                        ldr     r0, [r5]
+                       ldr     r5, [r5, #4]                    @ ddr1
+                       cmp     r5, #0
                        ldr     r4, =at91_rstc_base
                        ldr     r1, [r4]
 
@@ -30,6 +36,8 @@ at91sam9g45_restart:
 
                        .balign 32                              @ align to cache line
 
+                       strne   r2, [r5, #AT91_DDRSDRC_RTR]     @ disable DDR1 access
+                       strne   r3, [r5, #AT91_DDRSDRC_LPR]     @ power down DDR1
                        str     r2, [r0, #AT91_DDRSDRC_RTR]     @ disable DDR0 access
                        str     r3, [r0, #AT91_DDRSDRC_LPR]     @ power down DDR0
                        str     r4, [r1, #AT91_RSTC_CR]         @ reset processor
index 2919eba41ff4e908cd85f4d7eb3cc76a0e5fef56..c0e637adf65d2555adddaa1897730fc4021d04d7 100644 (file)
@@ -57,7 +57,7 @@ static irqreturn_t at91x40_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction at91x40_timer_irq = {
        .name           = "at91_tick",
-       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .flags          = IRQF_TIMER,
        .handler        = at91x40_timer_interrupt
 };
 
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 92b7f770615a83aaf59d5b81ef3526732185df86..4078ba93776b24ef9438f0dcc73c2f42dd859bd9 100644 (file)
@@ -176,7 +176,7 @@ static struct at24_platform_data eeprom_info = {
        .context        = (void *)0x7f00,
 };
 
-static struct snd_platform_data dm365_evm_snd_data = {
+static struct snd_platform_data dm365_evm_snd_data __maybe_unused = {
        .asp_chan_q = EVENTQ_3,
 };
 
index 52b8571b2e702a2e33b689983ca6fcc8632469bb..ce402cd21fa0a6f809963d71ca3cac3c6f650131 100644 (file)
@@ -15,8 +15,6 @@
 
 #include <mach/hardware.h>
 
-#include <linux/platform_device.h>
-
 #define DAVINCI_UART0_BASE     (IO_PHYS + 0x20000)
 #define DAVINCI_UART1_BASE     (IO_PHYS + 0x20400)
 #define DAVINCI_UART2_BASE     (IO_PHYS + 0x20800)
@@ -39,6 +37,8 @@
 #define UART_DM646X_SCR_TX_WATERMARK   0x08
 
 #ifndef __ASSEMBLY__
+#include <linux/platform_device.h>
+
 extern int davinci_serial_init(struct platform_device *);
 #endif
 
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 deb4b8093b30487821b5e43663adc594ae763958..0d40b35c557cba39980ad2644e6d4a97902f9555 100644 (file)
@@ -90,6 +90,7 @@ struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
        init.ops = &clk_fixup_mux_ops;
        init.parent_names = parents;
        init.num_parents = num_parents;
+       init.flags = 0;
 
        fixup_mux->mux.reg = reg;
        fixup_mux->mux.shift = shift;
index c3cfa4116dc09ffe22f2227c47130be0d900945e..c6b40f3867863c7de1a52e5a1ab72acdc23f758f 100644 (file)
@@ -285,7 +285,7 @@ int __init mx27_clocks_init(unsigned long fref)
        clk_register_clkdev(clk[ata_ahb_gate], "ata", NULL);
        clk_register_clkdev(clk[rtc_ipg_gate], NULL, "imx21-rtc");
        clk_register_clkdev(clk[scc_ipg_gate], "scc", NULL);
-       clk_register_clkdev(clk[cpu_div], NULL, "cpufreq-cpu0.0");
+       clk_register_clkdev(clk[cpu_div], NULL, "cpu0");
        clk_register_clkdev(clk[emi_ahb_gate], "emi_ahb" , NULL);
 
        mxc_timer_init(MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR), MX27_INT_GPT1);
index 1a56a33199976ed66907a80bce0336a03f40dcf2..7c0dc4540aa4785270784e3f62ce2b643fd95664 100644 (file)
@@ -328,7 +328,7 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,
        clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "imx-ssi.1");
        clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "imx-ssi.2");
        clk_register_clkdev(clk[sdma_gate], NULL, "imx35-sdma");
-       clk_register_clkdev(clk[cpu_podf], NULL, "cpufreq-cpu0.0");
+       clk_register_clkdev(clk[cpu_podf], NULL, "cpu0");
        clk_register_clkdev(clk[iim_gate], "iim", NULL);
        clk_register_clkdev(clk[dummy], NULL, "imx2-wdt.0");
        clk_register_clkdev(clk[dummy], NULL, "imx2-wdt.1");
@@ -397,7 +397,7 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
                                mx51_spdif_xtal_sel, ARRAY_SIZE(mx51_spdif_xtal_sel));
        clk[spdif1_sel] = imx_clk_mux("spdif1_sel", MXC_CCM_CSCMR2, 2, 2,
                                spdif_sel, ARRAY_SIZE(spdif_sel));
-       clk[spdif1_pred] = imx_clk_divider("spdif1_podf", "spdif1_sel", MXC_CCM_CDCDR, 16, 3);
+       clk[spdif1_pred] = imx_clk_divider("spdif1_pred", "spdif1_sel", MXC_CCM_CDCDR, 16, 3);
        clk[spdif1_podf] = imx_clk_divider("spdif1_podf", "spdif1_pred", MXC_CCM_CDCDR, 9, 6);
        clk[spdif1_com_sel] = imx_clk_mux("spdif1_com_sel", MXC_CCM_CSCMR2, 5, 1,
                                mx51_spdif1_com_sel, ARRAY_SIZE(mx51_spdif1_com_sel));
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 85a1b51346c8db12845d3123dd7758af034e3357..90372a21087f9ef38535479ccc35aac9e37977dc 100644 (file)
@@ -233,10 +233,15 @@ put_node:
        of_node_put(np);
 }
 
-static void __init imx6q_opp_init(struct device *cpu_dev)
+static void __init imx6q_opp_init(void)
 {
        struct device_node *np;
+       struct device *cpu_dev = get_cpu_device(0);
 
+       if (!cpu_dev) {
+               pr_warn("failed to get cpu0 device\n");
+               return;
+       }
        np = of_node_get(cpu_dev->of_node);
        if (!np) {
                pr_warn("failed to find cpu0 node\n");
@@ -268,7 +273,7 @@ static void __init imx6q_init_late(void)
                imx6q_cpuidle_init();
 
        if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) {
-               imx6q_opp_init(&imx6q_cpufreq_pdev.dev);
+               imx6q_opp_init();
                platform_device_register(&imx6q_cpufreq_pdev);
        }
 }
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 64ff37ea72b17455a1b5be7600ff7a1c16ceab16..80c177c36c5f25665ada2fbf93cf2ac4b007eee6 100644 (file)
@@ -117,6 +117,17 @@ void __init imx_init_l2cache(void)
        /* Configure the L2 PREFETCH and POWER registers */
        val = readl_relaxed(l2x0_base + L2X0_PREFETCH_CTRL);
        val |= 0x70800000;
+       /*
+        * The L2 cache controller(PL310) version on the i.MX6D/Q is r3p1-50rel0
+        * The L2 cache controller(PL310) version on the i.MX6DL/SOLO/SL is r3p2
+        * But according to ARM PL310 errata: 752271
+        * ID: 752271: Double linefill feature can cause data corruption
+        * Fault Status: Present in: r3p0, r3p1, r3p1-50rel0. Fixed in r3p2
+        * Workaround: The only workaround to this erratum is to disable the
+        * double linefill feature. This is the default behavior.
+        */
+       if (cpu_is_imx6q())
+               val &= ~(1 << 30 | 1 << 23);
        writel_relaxed(val, l2x0_base + L2X0_PREFETCH_CTRL);
        val = L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN;
        writel_relaxed(val, l2x0_base + L2X0_POWER_CTRL);
index 755fd29fed4a5f407ed3107abb4154637bdf5228..06a9e2e7d007b847f650b8efbf0856a1f47978ae 100644 (file)
@@ -1,2 +1,9 @@
 /* Simple oneliner include to the PCIv3 early init */
+#ifdef CONFIG_PCI
 extern int pci_v3_early_init(void);
+#else
+static inline int pci_v3_early_init(void)
+{
+       return 0;
+}
+#endif
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>
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 4c24303ec4816bfb6f1c4bc0695f57450a624517..58adf2fd9cfc98ea03f6b1f8cfe037ceb01bd78b 100644 (file)
@@ -140,6 +140,7 @@ int __init coherency_init(void)
                coherency_base = of_iomap(np, 0);
                coherency_cpu_base = of_iomap(np, 1);
                set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
+               of_node_put(np);
        }
 
        return 0;
@@ -147,9 +148,14 @@ int __init coherency_init(void)
 
 static int __init coherency_late_init(void)
 {
-       if (of_find_matching_node(NULL, of_coherency_table))
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, of_coherency_table);
+       if (np) {
                bus_register_notifier(&platform_bus_type,
                                      &mvebu_hwcc_platform_nb);
+               of_node_put(np);
+       }
        return 0;
 }
 
index 3cc4bef6401c160f2b8beb5c378889740424c546..27fc4f049474ed94b07cef00dfe3304b1165369c 100644 (file)
@@ -67,6 +67,7 @@ int __init armada_370_xp_pmsu_init(void)
                pr_info("Initializing Power Management Service Unit\n");
                pmsu_mp_base = of_iomap(np, 0);
                pmsu_reset_base = of_iomap(np, 1);
+               of_node_put(np);
        }
 
        return 0;
index f875124ff4f9e558ff9be36c08d6bbc9ab3fdf13..5175083cdb34650802288789c55a82aee8c20d08 100644 (file)
@@ -98,6 +98,7 @@ static int __init mvebu_system_controller_init(void)
                BUG_ON(!match);
                system_controller_base = of_iomap(np, 0);
                mvebu_sc = (struct mvebu_system_controller *)match->data;
+               of_node_put(np);
        }
 
        return 0;
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..87162e1b94a59104a2bca07114da5d8a02816fba 100644 (file)
@@ -129,6 +129,24 @@ DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)")
        .restart        = omap3xxx_restart,
 MACHINE_END
 
+static const char *omap36xx_boards_compat[] __initdata = {
+       "ti,omap36xx",
+       NULL,
+};
+
+DT_MACHINE_START(OMAP36XX_DT, "Generic OMAP36xx (Flattened Device Tree)")
+       .reserve        = omap_reserve,
+       .map_io         = omap3_map_io,
+       .init_early     = omap3630_init_early,
+       .init_irq       = omap_intc_of_init,
+       .handle_irq     = omap3_intc_handle_irq,
+       .init_machine   = omap_generic_init,
+       .init_late      = omap3_init_late,
+       .init_time      = omap3_sync32k_timer_init,
+       .dt_compat      = omap36xx_boards_compat,
+       .restart        = omap3xxx_restart,
+MACHINE_END
+
 static const char *omap3_gp_boards_compat[] __initdata = {
        "ti,omap3-beagle",
        "timll,omap3-devkit8000",
@@ -238,5 +256,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 c3270c0f1fce47724b0aba71d8f1ea388b94f445..f6fe388af9895ef8c8b2859f9177a146a30fb965 100644 (file)
@@ -167,38 +167,47 @@ static struct lp55xx_led_config rx51_lp5523_led_config[] = {
                .name           = "lp5523:kb1",
                .chan_nr        = 0,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:kb2",
                .chan_nr        = 1,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:kb3",
                .chan_nr        = 2,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:kb4",
                .chan_nr        = 3,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:b",
                .chan_nr        = 4,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:g",
                .chan_nr        = 5,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:r",
                .chan_nr        = 6,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:kb5",
                .chan_nr        = 7,
                .led_current    = 50,
+               .max_current    = 100,
        }, {
                .name           = "lp5523:kb6",
                .chan_nr        = 8,
                .led_current    = 50,
+               .max_current    = 100,
        }
 };
 
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..b237950eb8a319f9fb879d051245cc7c6fea6968 100644 (file)
@@ -1632,7 +1632,7 @@ static struct omap_clk omap44xx_clks[] = {
        CLK(NULL,       "auxclk5_src_ck",               &auxclk5_src_ck),
        CLK(NULL,       "auxclk5_ck",                   &auxclk5_ck),
        CLK(NULL,       "auxclkreq5_ck",                &auxclkreq5_ck),
-       CLK("omap-gpmc",        "fck",                  &dummy_ck),
+       CLK("50000000.gpmc",    "fck",                  &dummy_ck),
        CLK("omap_i2c.1",       "ick",                  &dummy_ck),
        CLK("omap_i2c.2",       "ick",                  &dummy_ck),
        CLK("omap_i2c.3",       "ick",                  &dummy_ck),
@@ -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 c443f2e97e103702531c79b70dccebc11a85218d..4c8982ae95295f508c1fc6610f8c47d1e1c8137d 100644 (file)
@@ -143,7 +143,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
         * Call idle CPU cluster PM exit notifier chain
         * to restore GIC and wakeupgen context.
         */
-       if ((cx->mpu_state == PWRDM_POWER_RET) &&
+       if (dev->cpu == 0 && (cx->mpu_state == PWRDM_POWER_RET) &&
                (cx->mpu_logic_state == PWRDM_POWER_OFF))
                cpu_cluster_pm_exit();
 
index 73ae7536a32b7bd24040e385dc218027e5b7c600..5c5315ba129b705b4af0c6b9f8af38e217e922cd 100644 (file)
@@ -530,12 +530,12 @@ static int __init omap2_init_devices(void)
                omap_init_mcspi();
                omap_init_sham();
                omap_init_aes();
+               omap_init_rng();
        } else {
                /* These can be removed when bindings are done */
                omap_init_wl12xx_of();
        }
        omap_init_sti();
-       omap_init_rng();
        omap_init_vout();
 
        return 0;
index 64b5a83469822ad53693c2ae8ffdd3b227fa2a7b..8b6876c98ce1a320c793e7485c35d23bd3a5b923 100644 (file)
@@ -272,9 +272,19 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
        struct gpmc_timings t;
        int ret;
 
-       if (gpmc_onenand_data->of_node)
+       if (gpmc_onenand_data->of_node) {
                gpmc_read_settings_dt(gpmc_onenand_data->of_node,
                                      &onenand_async);
+               if (onenand_async.sync_read || onenand_async.sync_write) {
+                       if (onenand_async.sync_write)
+                               gpmc_onenand_data->flags |=
+                                       ONENAND_SYNC_READWRITE;
+                       else
+                               gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
+                       onenand_async.sync_read = false;
+                       onenand_async.sync_write = false;
+               }
+       }
 
        omap2_onenand_set_async_mode(onenand_base);
 
index 9f4795aff48aae5eedcf874284bb88b9b3b2d777..579697adaae7dfd373285979eebeb815658f4a1d 100644 (file)
@@ -1491,8 +1491,8 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
         */
        ret = gpmc_cs_remap(cs, res.start);
        if (ret < 0) {
-               dev_err(&pdev->dev, "cannot remap GPMC CS %d to 0x%x\n",
-                       cs, res.start);
+               dev_err(&pdev->dev, "cannot remap GPMC CS %d to %pa\n",
+                       cs, &res.start);
                goto err;
        }
 
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 5d2080ef7923585c1313f598a40961c3b241d1ce..16f78a990d04cafbd7dd1fcaa81b7d7dd061e979 100644 (file)
@@ -28,7 +28,7 @@
 #define OMAP_PULL_UP                   (1 << 4)
 #define OMAP_ALTELECTRICALSEL          (1 << 5)
 
-/* 34xx specific mux bit defines */
+/* omap3/4/5 specific mux bit defines */
 #define OMAP_INPUT_EN                  (1 << 8)
 #define OMAP_OFF_EN                    (1 << 9)
 #define OMAP_OFFOUT_EN                 (1 << 10)
@@ -36,8 +36,6 @@
 #define OMAP_OFF_PULL_EN               (1 << 12)
 #define OMAP_OFF_PULL_UP               (1 << 13)
 #define OMAP_WAKEUP_EN                 (1 << 14)
-
-/* 44xx specific mux bit defines */
 #define OMAP_WAKEUP_EVENT              (1 << 15)
 
 /* Active pin states */
index c53609f4629485b46277aad1e0bdb5634f244c84..be271f1d585bfb5825e22edb93157dde999a6234 100644 (file)
@@ -620,7 +620,7 @@ static struct omap_mux __initdata omap3_muxmodes[] = {
                "uart1_rts", "ssi1_flag_tx", NULL, NULL,
                "gpio_149", NULL, NULL, "safe_mode"),
        _OMAP3_MUXENTRY(UART1_RX, 151,
-               "uart1_rx", "ss1_wake_tx", "mcbsp1_clkr", "mcspi4_clk",
+               "uart1_rx", "ssi1_wake_tx", "mcbsp1_clkr", "mcspi4_clk",
                "gpio_151", NULL, NULL, "safe_mode"),
        _OMAP3_MUXENTRY(UART1_TX, 148,
                "uart1_tx", "ssi1_dat_tx", NULL, NULL,
index 8708b2a9da453e91be9bc16590d48e9652b35508..89121109329533b917561f4da6ce4b335872f4c4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * OMAP4 SMP source file. It contains platform specific fucntions
+ * OMAP4 SMP source file. It contains platform specific functions
  * needed for the linux smp kernel.
  *
  * Copyright (C) 2009 Texas Instruments, Inc.
index f99f68e1e85bd3748c5965a0bd27c47d0f6d538e..b69dd9abb50aeb0003998b24d7df9063a6a41cb1 100644 (file)
@@ -158,7 +158,7 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
        }
 
        od = omap_device_alloc(pdev, hwmods, oh_cnt);
-       if (!od) {
+       if (IS_ERR(od)) {
                dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
                        oh_name);
                ret = PTR_ERR(od);
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 fa74a0625da1a033335ea5fb76d6738889a9a1aa..ead48fa5715e16fb197dfa4fac56b0f71069bd20 100644 (file)
@@ -628,7 +628,7 @@ void __init omap4_local_timer_init(void)
 #endif /* CONFIG_HAVE_ARM_TWD */
 #endif /* CONFIG_ARCH_OMAP4 */
 
-#ifdef CONFIG_SOC_OMAP5
+#if defined(CONFIG_SOC_OMAP5) || defined(CONFIG_SOC_DRA7XX)
 void __init omap5_realtime_timer_init(void)
 {
        omap4_sync32k_timer_init();
@@ -636,7 +636,7 @@ void __init omap5_realtime_timer_init(void)
 
        clocksource_of_init();
 }
-#endif /* CONFIG_SOC_OMAP5 */
+#endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */
 
 /**
  * omap_timer_init - build and register timer device with an
index 612a45689770752bc9e1319d2eeb430ae36a449c..7fb96ebdc0fbc74d37b1122fe0462026031a8889 100644 (file)
@@ -289,7 +289,7 @@ static void collie_flash_exit(void)
 }
 
 static struct flash_platform_data collie_flash_data = {
-       .map_name       = "cfi_probe",
+       .map_name       = "jedec_probe",
        .init           = collie_flash_init,
        .set_vpp        = collie_set_vpp,
        .exit           = collie_flash_exit,
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..7f8f6076d3609e82382bb98f116df3bfc59049ed 100644 (file)
@@ -1108,9 +1108,9 @@ static const struct pinctrl_map eva_pinctrl_map[] = {
        PIN_MAP_MUX_GROUP_DEFAULT("asoc-simple-card.1", "pfc-r8a7740",
                                  "fsib_mclk_in", "fsib"),
        /* GETHER */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-eth", "pfc-r8a7740",
+       PIN_MAP_MUX_GROUP_DEFAULT("r8a7740-gether", "pfc-r8a7740",
                                  "gether_mii", "gether"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-eth", "pfc-r8a7740",
+       PIN_MAP_MUX_GROUP_DEFAULT("r8a7740-gether", "pfc-r8a7740",
                                  "gether_int", "gether"),
        /* HDMI */
        PIN_MAP_MUX_GROUP_DEFAULT("sh-mobile-hdmi", "pfc-r8a7740",
@@ -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..5930af8d434fb90c4a79fd8b0f8c225be9b93b58 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_data/gpio-rcar.h>
 #include <linux/platform_device.h>
+#include <linux/phy.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/sh_eth.h>
@@ -96,7 +97,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,
 };
@@ -156,6 +156,30 @@ static void __init lager_add_standard_devices(void)
                                          &ether_pdata, sizeof(ether_pdata));
 }
 
+/*
+ * Ether LEDs on the Lager board are named LINK and ACTIVE which corresponds
+ * to non-default 01 setting of the Micrel KSZ8041 PHY control register 1 bits
+ * 14-15. We have to set them back to 01 from the default 00 value each time
+ * the PHY is reset. It's also important because the PHY's LED0 signal is
+ * connected to SoC's ETH_LINK signal and in the PHY's default mode it will
+ * bounce on and off after each packet, which we apparently want to avoid.
+ */
+static int lager_ksz8041_fixup(struct phy_device *phydev)
+{
+       u16 phyctrl1 = phy_read(phydev, 0x1e);
+
+       phyctrl1 &= ~0xc000;
+       phyctrl1 |= 0x4000;
+       return phy_write(phydev, 0x1e, phyctrl1);
+}
+
+static void __init lager_init(void)
+{
+       lager_add_standard_devices();
+
+       phy_register_fixup_for_id("r8a7790-ether-ff:01", lager_ksz8041_fixup);
+}
+
 static const char *lager_boards_compat_dt[] __initdata = {
        "renesas,lager",
        NULL,
@@ -164,6 +188,6 @@ static const char *lager_boards_compat_dt[] __initdata = {
 DT_MACHINE_START(LAGER_DT, "lager")
        .init_early     = r8a7790_init_delay,
        .init_time      = r8a7790_timer_init,
-       .init_machine   = lager_add_standard_devices,
+       .init_machine   = lager_init,
        .dt_compat      = lager_boards_compat_dt,
 MACHINE_END
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 8ea5ef6c79ccbed859318cc69745488c0d273290..5bd2e851e3c7f2d03cd7ae4dd647ec1cc7d9c537 100644 (file)
@@ -555,7 +555,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("pll2h",                  &pll2h_clk),
 
        /* CPU clock */
-       CLKDEV_DEV_ID("cpufreq-cpu0",           &z_clk),
+       CLKDEV_DEV_ID("cpu0",                   &z_clk),
 
        /* DIV6 */
        CLKDEV_CON_ID("zb",                     &div6_clks[DIV6_ZB]),
index 1942eaef518134804110ed14cc5a61c94550af27..c92c023f0d27c1de8778665e372d1abfba82db42 100644 (file)
@@ -616,7 +616,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("smp_twd", &twd_clk), /* smp_twd */
 
        /* DIV4 clocks */
-       CLKDEV_DEV_ID("cpufreq-cpu0", &div4_clks[DIV4_Z]),
+       CLKDEV_DEV_ID("cpu0", &div4_clks[DIV4_Z]),
 
        /* DIV6 clocks */
        CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
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 a85adcd00882e4ad193cd3b177179a5ad8162e6a..a1659863bfd5cb650338d6d8919ab0b145da1d57 100644 (file)
@@ -1,7 +1,3 @@
-menu "ST-Ericsson AB U300/U335 Platform"
-
-comment "ST-Ericsson Mobile Platform Products"
-
 config ARCH_U300
        bool "ST-Ericsson U300 Series" if ARCH_MULTI_V5
        depends on MMU
@@ -25,7 +21,9 @@ config ARCH_U300
        help
          Support for ST-Ericsson U300 series mobile platforms.
 
-comment "ST-Ericsson U300/U335 Feature Selections"
+if ARCH_U300
+
+menu "ST-Ericsson AB U300/U335 Platform"
 
 config MACH_U300
        depends on ARCH_U300
@@ -53,3 +51,5 @@ config MACH_U300_SPIDUMMY
                SPI framework and ARM PL022 support.
 
 endmenu
+
+endif
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 82ccf1d98735520ef4727c615398e478fccb8b02..264f894c0e3d228ca62280deb0aaec8b350a2fa1 100644 (file)
@@ -69,6 +69,7 @@ static int __init ux500_l2x0_init(void)
         * some SMI service available.
         */
        outer_cache.disable = NULL;
+       outer_cache.set_debug = NULL;
 
        return 0;
 }
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..e6eb4819291241f30b51d5e7b58c14d1d07c0d32 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>
@@ -130,6 +131,16 @@ static void tc2_pm_down(u64 residency)
        } else
                BUG();
 
+       /*
+        * If the CPU is committed to power down, make sure
+        * the power controller will be in charge of waking it
+        * up upon IRQ, ie IRQ lines are cut from GIC CPU IF
+        * to the CPU by disabling the GIC CPU IF to prevent wfi
+        * from completing execution behind power controller back
+        */
+       if (!skip_wfi)
+               gic_cpu_if_down();
+
        if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
                arch_spin_unlock(&tc2_pm_lock);
 
index f5e1a8471714cd421e2ab9dee54ae88f144316d1..1272ed202ddee97c2a9143d97afbf4bed69f0fea 100644 (file)
@@ -1232,7 +1232,8 @@ __iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
                                break;
 
                len = (j - i) << PAGE_SHIFT;
-               ret = iommu_map(mapping->domain, iova, phys, len, 0);
+               ret = iommu_map(mapping->domain, iova, phys, len,
+                               IOMMU_READ|IOMMU_WRITE);
                if (ret < 0)
                        goto fail;
                iova += len;
@@ -1431,6 +1432,27 @@ static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
                                         GFP_KERNEL);
 }
 
+static int __dma_direction_to_prot(enum dma_data_direction dir)
+{
+       int prot;
+
+       switch (dir) {
+       case DMA_BIDIRECTIONAL:
+               prot = IOMMU_READ | IOMMU_WRITE;
+               break;
+       case DMA_TO_DEVICE:
+               prot = IOMMU_READ;
+               break;
+       case DMA_FROM_DEVICE:
+               prot = IOMMU_WRITE;
+               break;
+       default:
+               prot = 0;
+       }
+
+       return prot;
+}
+
 /*
  * Map a part of the scatter-gather list into contiguous io address space
  */
@@ -1444,6 +1466,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
        int ret = 0;
        unsigned int count;
        struct scatterlist *s;
+       int prot;
 
        size = PAGE_ALIGN(size);
        *handle = DMA_ERROR_CODE;
@@ -1460,7 +1483,9 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
                        !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
                        __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
 
-               ret = iommu_map(mapping->domain, iova, phys, len, 0);
+               prot = __dma_direction_to_prot(dir);
+
+               ret = iommu_map(mapping->domain, iova, phys, len, prot);
                if (ret < 0)
                        goto fail;
                count += len >> PAGE_SHIFT;
@@ -1665,19 +1690,7 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p
        if (dma_addr == DMA_ERROR_CODE)
                return dma_addr;
 
-       switch (dir) {
-       case DMA_BIDIRECTIONAL:
-               prot = IOMMU_READ | IOMMU_WRITE;
-               break;
-       case DMA_TO_DEVICE:
-               prot = IOMMU_READ;
-               break;
-       case DMA_FROM_DEVICE:
-               prot = IOMMU_WRITE;
-               break;
-       default:
-               prot = 0;
-       }
+       prot = __dma_direction_to_prot(dir);
 
        ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, prot);
        if (ret < 0)
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..18ec4c504abf908ac9ddca01a4458a8183c6cc95 100644 (file)
@@ -77,7 +77,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 +207,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);
 
 /*
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 1a6bfe954d4926de3a8dcee10fdbe0b0698279b3..835c559786bda923fe0cb8616b3031932a86bb21 100644 (file)
@@ -6,13 +6,6 @@ config FRAME_POINTER
        bool
        default y
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T output.
-
 config EARLY_PRINTK
        bool "Early printk support"
        default y
index 5b3e83217b03b1e255c23347fcc4d06859cba9c1..31c81e9b792e21b5078ada9f4299fc55e3071f86 100644 (file)
@@ -42,7 +42,7 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
-# CONFIG_BLK_DEV is not set
+CONFIG_BLK_DEV=y
 CONFIG_SCSI=y
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=y
@@ -72,6 +72,7 @@ CONFIG_LOGO=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 # CONFIG_EXT3_FS_XATTR is not set
 CONFIG_FUSE_FS=y
@@ -90,3 +91,5 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_FTRACE is not set
 CONFIG_ATOMIC64_SELFTEST=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_BLK=y
index 6d4482fa35bcbc183bf64d9239a4a5a87bb86705..e2950b098e76f68803559ca264d7bed94ffa4789 100644 (file)
@@ -43,6 +43,6 @@
                                 COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
                                 COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV)
 
-extern unsigned int elf_hwcap;
+extern unsigned long elf_hwcap;
 #endif
 #endif
index edb3d5c73a3232c35532bd5e489add1cabf7201c..7ecc2b23882e44c62055ba2a57d49833ae119850 100644 (file)
@@ -166,9 +166,10 @@ do {                                                                       \
 
 #define get_user(x, ptr)                                               \
 ({                                                                     \
+       __typeof__(*(ptr)) __user *__p = (ptr);                         \
        might_fault();                                                  \
-       access_ok(VERIFY_READ, (ptr), sizeof(*(ptr))) ?                 \
-               __get_user((x), (ptr)) :                                \
+       access_ok(VERIFY_READ, __p, sizeof(*__p)) ?                     \
+               __get_user((x), __p) :                                  \
                ((x) = 0, -EFAULT);                                     \
 })
 
@@ -227,9 +228,10 @@ do {                                                                       \
 
 #define put_user(x, ptr)                                               \
 ({                                                                     \
+       __typeof__(*(ptr)) __user *__p = (ptr);                         \
        might_fault();                                                  \
-       access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) ?                \
-               __put_user((x), (ptr)) :                                \
+       access_ok(VERIFY_WRITE, __p, sizeof(*__p)) ?                    \
+               __put_user((x), __p) :                                  \
                -EFAULT;                                                \
 })
 
index 1f2e4d5a5c0fd65ec86d5f487256dc7de9c4584e..bb785d23dbde8764d1a53df79ef4a7b96dc48966 100644 (file)
@@ -80,8 +80,10 @@ void fpsimd_thread_switch(struct task_struct *next)
 
 void fpsimd_flush_thread(void)
 {
+       preempt_disable();
        memset(&current->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
        fpsimd_load_state(&current->thread.fpsimd_state);
+       preempt_enable();
 }
 
 #ifdef CONFIG_KERNEL_MODE_NEON
index 57fb55c44c901c19c7264f02ff44d6c481fadc56..7ae8a1f00c3c82bf256f716aee79aaf24fac8f1b 100644 (file)
@@ -143,15 +143,26 @@ void machine_restart(char *cmd)
 
 void __show_regs(struct pt_regs *regs)
 {
-       int i;
+       int i, top_reg;
+       u64 lr, sp;
+
+       if (compat_user_mode(regs)) {
+               lr = regs->compat_lr;
+               sp = regs->compat_sp;
+               top_reg = 12;
+       } else {
+               lr = regs->regs[30];
+               sp = regs->sp;
+               top_reg = 29;
+       }
 
        show_regs_print_info(KERN_DEFAULT);
        print_symbol("PC is at %s\n", instruction_pointer(regs));
-       print_symbol("LR is at %s\n", regs->regs[30]);
+       print_symbol("LR is at %s\n", lr);
        printk("pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n",
-              regs->pc, regs->regs[30], regs->pstate);
-       printk("sp : %016llx\n", regs->sp);
-       for (i = 29; i >= 0; i--) {
+              regs->pc, lr, regs->pstate);
+       printk("sp : %016llx\n", sp);
+       for (i = top_reg; i >= 0; i--) {
                printk("x%-2d: %016llx ", i, regs->regs[i]);
                if (i % 2 == 0)
                        printk("\n");
index bca4c1c2052ad87af9d883bef4a4e70b2524a128..055cfb80e05c5d8d352880cb6db85d2cdea38241 100644 (file)
@@ -57,7 +57,7 @@
 unsigned int processor_id;
 EXPORT_SYMBOL(processor_id);
 
-unsigned int elf_hwcap __read_mostly;
+unsigned long elf_hwcap __read_mostly;
 EXPORT_SYMBOL_GPL(elf_hwcap);
 
 static const char *cpu_name;
@@ -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..c23751b0612033f56533955788eabefa6c5fd39e 100644 (file)
@@ -130,7 +130,7 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
        force_sig_info(sig, &si, tsk);
 }
 
-void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs)
+static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs)
 {
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->active_mm;
@@ -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 8ae80a18e8ecbf18acd29a0aed49c70d5ecbdbea..19da91e0cd278911ec8400449d199325e528f00b 100644 (file)
@@ -35,7 +35,7 @@
  */
 ENTRY(__cpu_flush_user_tlb_range)
        vma_vm_mm x3, x2                        // get vma->vm_mm
-       mmid    x3, x3                          // get vm_mm->context.id
+       mmid    w3, x3                          // get vm_mm->context.id
        dsb     sy
        lsr     x0, x0, #12                     // align address
        lsr     x1, x1, #12
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 d22af851f3f638b09fdc4394a05e2cebf8a10201..fd7980743890b2ebcf5ff9b5ca40fc4ef83de220 100644 (file)
@@ -1,5 +1,19 @@
 
 generic-y      += clkdev.h
+generic-y       += cputime.h
+generic-y       += delay.h
+generic-y       += device.h
+generic-y       += div64.h
+generic-y       += emergency-restart.h
 generic-y      += exec.h
-generic-y      += trace_clock.h
+generic-y       += futex.h
+generic-y       += irq_regs.h
 generic-y      += param.h
+generic-y       += local.h
+generic-y       += local64.h
+generic-y       += percpu.h
+generic-y       += scatterlist.h
+generic-y       += sections.h
+generic-y       += topology.h
+generic-y      += trace_clock.h
+generic-y       += xor.h
diff --git a/arch/avr32/include/asm/cputime.h b/arch/avr32/include/asm/cputime.h
deleted file mode 100644 (file)
index e87e0f8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_CPUTIME_H
-#define __ASM_AVR32_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __ASM_AVR32_CPUTIME_H */
diff --git a/arch/avr32/include/asm/delay.h b/arch/avr32/include/asm/delay.h
deleted file mode 100644 (file)
index 9670e12..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/delay.h>
diff --git a/arch/avr32/include/asm/device.h b/arch/avr32/include/asm/device.h
deleted file mode 100644 (file)
index d8f9872..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Arch specific extensions to struct device
- *
- * This file is released under the GPLv2
- */
-#include <asm-generic/device.h>
-
diff --git a/arch/avr32/include/asm/div64.h b/arch/avr32/include/asm/div64.h
deleted file mode 100644 (file)
index d7ddd4f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_DIV64_H
-#define __ASM_AVR32_DIV64_H
-
-#include <asm-generic/div64.h>
-
-#endif /* __ASM_AVR32_DIV64_H */
diff --git a/arch/avr32/include/asm/emergency-restart.h b/arch/avr32/include/asm/emergency-restart.h
deleted file mode 100644 (file)
index 3e7e014..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_EMERGENCY_RESTART_H
-#define __ASM_AVR32_EMERGENCY_RESTART_H
-
-#include <asm-generic/emergency-restart.h>
-
-#endif /* __ASM_AVR32_EMERGENCY_RESTART_H */
diff --git a/arch/avr32/include/asm/futex.h b/arch/avr32/include/asm/futex.h
deleted file mode 100644 (file)
index 10419f1..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_FUTEX_H
-#define __ASM_AVR32_FUTEX_H
-
-#include <asm-generic/futex.h>
-
-#endif /* __ASM_AVR32_FUTEX_H */
diff --git a/arch/avr32/include/asm/irq_regs.h b/arch/avr32/include/asm/irq_regs.h
deleted file mode 100644 (file)
index 3dd9c0b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/irq_regs.h>
diff --git a/arch/avr32/include/asm/local.h b/arch/avr32/include/asm/local.h
deleted file mode 100644 (file)
index 1c16196..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_LOCAL_H
-#define __ASM_AVR32_LOCAL_H
-
-#include <asm-generic/local.h>
-
-#endif /* __ASM_AVR32_LOCAL_H */
diff --git a/arch/avr32/include/asm/local64.h b/arch/avr32/include/asm/local64.h
deleted file mode 100644 (file)
index 36c93b5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/local64.h>
diff --git a/arch/avr32/include/asm/percpu.h b/arch/avr32/include/asm/percpu.h
deleted file mode 100644 (file)
index 69227b4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_PERCPU_H
-#define __ASM_AVR32_PERCPU_H
-
-#include <asm-generic/percpu.h>
-
-#endif /* __ASM_AVR32_PERCPU_H */
diff --git a/arch/avr32/include/asm/scatterlist.h b/arch/avr32/include/asm/scatterlist.h
deleted file mode 100644 (file)
index a5902d9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_SCATTERLIST_H
-#define __ASM_AVR32_SCATTERLIST_H
-
-#include <asm-generic/scatterlist.h>
-
-#endif /* __ASM_AVR32_SCATTERLIST_H */
diff --git a/arch/avr32/include/asm/sections.h b/arch/avr32/include/asm/sections.h
deleted file mode 100644 (file)
index aa14252..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_SECTIONS_H
-#define __ASM_AVR32_SECTIONS_H
-
-#include <asm-generic/sections.h>
-
-#endif /* __ASM_AVR32_SECTIONS_H */
diff --git a/arch/avr32/include/asm/topology.h b/arch/avr32/include/asm/topology.h
deleted file mode 100644 (file)
index 5b766cb..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_AVR32_TOPOLOGY_H
-#define __ASM_AVR32_TOPOLOGY_H
-
-#include <asm-generic/topology.h>
-
-#endif /* __ASM_AVR32_TOPOLOGY_H */
diff --git a/arch/avr32/include/asm/xor.h b/arch/avr32/include/asm/xor.h
deleted file mode 100644 (file)
index 99c87aa..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_XOR_H
-#define _ASM_XOR_H
-
-#include <asm-generic/xor.h>
-
-#endif
index c2731003edef556c18cd137f4a0b1aac5e770cc3..42a53e740a7ee1c93044a01742e93250dc919346 100644 (file)
@@ -289,7 +289,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
                memset(childregs, 0, sizeof(struct pt_regs));
                p->thread.cpu_context.r0 = arg;
                p->thread.cpu_context.r1 = usp; /* fn */
-               p->thread.cpu_context.r2 = syscall_return;
+               p->thread.cpu_context.r2 = (unsigned long)syscall_return;
                p->thread.cpu_context.pc = (unsigned long)ret_from_kernel_thread;
                childregs->sr = MODE_SUPERVISOR;
        } else {
index 869a1c6ffeee944a64608d996877a78ee3499245..12f828ad5058d09158f8d3e2007b76a7a42cbb4a 100644 (file)
@@ -98,7 +98,14 @@ static void comparator_mode(enum clock_event_mode mode,
        case CLOCK_EVT_MODE_SHUTDOWN:
                sysreg_write(COMPARE, 0);
                pr_debug("%s: stop\n", evdev->name);
-               cpu_idle_poll_ctrl(false);
+               if (evdev->mode == CLOCK_EVT_MODE_ONESHOT ||
+                   evdev->mode == CLOCK_EVT_MODE_RESUME) {
+                       /*
+                        * Only disable idle poll if we have forced that
+                        * in a previous call.
+                        */
+                       cpu_idle_poll_ctrl(false);
+               }
                break;
        default:
                BUG();
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 4a9baa9f63300cab298d913009c3d840d8adbc12..9969dbab19e36e3f2bd1210c93840bc85bfd7f16 100644 (file)
@@ -276,7 +276,7 @@ static struct platform_device mtx1_pci_host = {
        .resource       = alchemy_pci_host_res,
 };
 
-static struct __initdata platform_device * mtx1_devs[] = {
+static struct platform_device *mtx1_devs[] __initdata = {
        &mtx1_pci_host,
        &mtx1_gpio_leds,
        &mtx1_wdt,
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..d445d060e346ab689a177bf584cfebd5b9dfca51 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.
 
 /*
  * MIPS32, MIPS64, VR5500, IDT32332, IDT32334 and maybe a few other
- * pre-MIPS32/MIPS53 processors have CLO, CLZ. The IDT RC64574 is 64-bit and
+ * pre-MIPS32/MIPS64 processors have CLO, CLZ. The IDT RC64574 is 64-bit and
  * has CLO and CLZ but not DCLO nor DCLZ.  For 64-bit kernels
  * cpu_has_clo_clz also indicates the availability of DCLO and DCLZ.
  */
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 */
index 4d6d77ed9b9d679cd955e2fafe2dbc16527db65c..e194f957ca8c42a0af82f0621c425308a25e4d53 100644 (file)
@@ -22,7 +22,7 @@
 
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-       asm goto("1:\tnop\n\t"
+       asm_volatile_goto("1:\tnop\n\t"
                "nop\n\t"
                ".pushsection __jump_table,  \"aw\"\n\t"
                WORD_INSN " 1b, %l[l_yes], %0\n\t"
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 4204d76af854209659de87b35e143ec85fb802da..029e002a4ea0083d626140961d3cd465b188fabc 100644 (file)
@@ -73,7 +73,7 @@
 3:
 
 #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
-       PTR_L   t8, __stack_chk_guard
+       PTR_LA  t8, __stack_chk_guard
        LONG_L  t9, TASK_STACK_CANARY(a1)
        LONG_S  t9, 0(t8)
 #endif
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 38af83f84c4af846ce2a6fb55994804b4d781bdc..20b7b040e76f1c4e8d9a019edae6014f3ee3fea5 100644 (file)
@@ -67,7 +67,7 @@ LEAF(resume)
 1:
 
 #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
-       PTR_L   t8, __stack_chk_guard
+       PTR_LA  t8, __stack_chk_guard
        LONG_L  t9, TASK_STACK_CANARY(a1)
        LONG_S  t9, 0(t8)
 #endif
index 921238a6bd260d238cd2a01e177556ed105c770b..078de5eaca8fd96d8bcb720491fe3f56901dc03c 100644 (file)
@@ -69,7 +69,7 @@
 1:
 
 #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
-       PTR_L   t8, __stack_chk_guard
+       PTR_LA  t8, __stack_chk_guard
        LONG_L  t9, TASK_STACK_CANARY(a1)
        LONG_S  t9, 0(t8)
 #endif
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..bc6f96fcb529d53d16a04b09754a9e4395fd457f 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,11 +603,13 @@ 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();
                else
                        blast_scache_range(addr, addr + size);
+               preempt_enable();
                __sync();
                return;
        }
@@ -621,6 +625,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 +636,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();
@@ -645,6 +651,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
                         */
                        blast_inv_scache_range(addr, addr + size);
                }
+               preempt_enable();
                __sync();
                return;
        }
@@ -655,6 +662,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 +788,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 +827,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 +1043,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 +1064,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 +1084,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 +1097,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 +1226,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 +1403,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..5f8b955125801935f33370559476ca93f640c4df 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);
 }
@@ -303,12 +308,10 @@ static void mips_dma_sync_sg_for_cpu(struct device *dev,
 {
        int i;
 
-       /* 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))
+               for (i = 0; i < nelems; i++, sg++)
                        __dma_sync(sg_page(sg), sg->offset, sg->length,
                                   direction);
-       }
 }
 
 static void mips_dma_sync_sg_for_device(struct device *dev,
@@ -316,12 +319,10 @@ static void mips_dma_sync_sg_for_device(struct device *dev,
 {
        int i;
 
-       /* Make sure that gcc doesn't leave the empty loop body.  */
-       for (i = 0; i < nelems; i++, sg++) {
-               if (!plat_device_is_coherent(dev))
+       if (!plat_device_is_coherent(dev))
+               for (i = 0; i < nelems; i++, sg++)
                        __dma_sync(sg_page(sg), sg->offset, sg->length,
                                   direction);
-       }
 }
 
 int mips_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
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 eb59bfe23e8510c7c812d43496860bcee37974b7..93c9980e1b6b61a93c81dc93a4c0902ee59a451c 100644 (file)
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  */
-
-#include <linux/of.h>  /* linux/of.h gets to determine #include ordering */
-
 #ifndef _ASM_OPENRISC_PROM_H
 #define _ASM_OPENRISC_PROM_H
-#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
 
-#include <linux/types.h>
-#include <asm/irq.h>
-#include <linux/irqdomain.h>
-#include <linux/atomic.h>
-#include <linux/of_irq.h>
-#include <linux/of_fdt.h>
-#include <linux/of_address.h>
-#include <linux/proc_fs.h>
-#include <linux/platform_device.h>
 #define HAVE_ARCH_DEVTREE_FIXUPS
 
-/* Other Prototypes */
-extern int early_uartlite_console(void);
-
-/* Parse the ibm,dma-window property of an OF node into the busno, phys and
- * size parameters.
- */
-void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
-               unsigned long *busno, unsigned long *phys, unsigned long *size);
-
-extern void kdump_move_device_tree(void);
-
-/* Get the MAC address */
-extern const void *of_get_mac_address(struct device_node *np);
-
-/**
- * of_irq_map_pci - Resolve the interrupt for a PCI device
- * @pdev:      the device whose interrupt is to be resolved
- * @out_irq:   structure of_irq filled by this function
- *
- * This function resolves the PCI interrupt for a given PCI device. If a
- * device-node exists for a given pci_dev, it will use normal OF tree
- * walking. If not, it will implement standard swizzling and walk up the
- * PCI tree until an device-node is found, at which point it will finish
- * resolving using the OF tree walking.
- */
-struct pci_dev;
-extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
-
-#endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
 #endif /* _ASM_OPENRISC_PROM_H */
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 0f90569b9d8546f7fa710a5b15f7883266e1ba95..9387cc2693f6a33a70459fcb46da058db395e2c4 100644 (file)
@@ -40,6 +40,8 @@ CONFIG_IP_NF_QUEUE=m
 CONFIG_LLC2=m
 CONFIG_NET_PKTGEN=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_PARPORT=y
index b647b182dacc17d6cf95fa79cee892fd8e0427bf..90025322b75ecd3b8a5672b76d18ce534b92ee2f 100644 (file)
@@ -79,6 +79,8 @@ CONFIG_IP_DCCP=m
 CONFIG_LLC2=m
 CONFIG_NET_PKTGEN=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_BLK_DEV_UMEM=m
index e289f5bf31488f0bb9eff29bb51bcbf25abd3bd1..f1a0c25bef8dc3a6667c608a092f96a39d5994aa 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODVERSIONS=y
@@ -27,6 +28,8 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
index 311ca367b62237b87bb78023f7687ef1f7d98c85..ec1b014952b6601458f4c3b2901d8e86670b96fc 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
@@ -39,6 +40,8 @@ CONFIG_NETFILTER_DEBUG=y
 CONFIG_IP_NF_QUEUE=m
 CONFIG_NET_PKTGEN=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_BLK_DEV_UMEM=m
index f11006361297eb152cf5f78471f6c69de41e5cfc..e1c8d2015c8938ac0a3440d38af427b4ac8eec7a 100644 (file)
@@ -62,6 +62,8 @@ CONFIG_TIPC=m
 CONFIG_LLC2=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
index dfe88f6c95c4d7c924b9e03d8c7abd236f100609..ba61495e1fa4b8d9ee576aff9a7559e619f229b6 100644 (file)
@@ -49,6 +49,8 @@ CONFIG_INET6_ESP=y
 CONFIG_INET6_IPCOMP=y
 CONFIG_LLC2=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_PARPORT=y
index 1945f995f2dfec1212ed8e1769168085076d9bb1..4736020ba5eabeb05841e5a9dc4834026f61a92d 100644 (file)
@@ -6,7 +6,7 @@ struct pt_regs;
 
 /* traps.c */
 void parisc_terminate(char *msg, struct pt_regs *regs,
-               int code, unsigned long offset);
+               int code, unsigned long offset) __noreturn __cold;
 
 /* mm/fault.c */
 void do_page_fault(struct pt_regs *regs, unsigned long code,
index 8a252f2d6c087aad6248e98178c79eef818c14da..2b96602e812ff9648f0ce9ec66b52e103ddb8a3e 100644 (file)
@@ -72,7 +72,6 @@ enum ipi_message_type {
        IPI_NOP=0,
        IPI_RESCHEDULE=1,
        IPI_CALL_FUNC,
-       IPI_CALL_FUNC_SINGLE,
        IPI_CPU_START,
        IPI_CPU_STOP,
        IPI_CPU_TEST
@@ -164,11 +163,6 @@ ipi_interrupt(int irq, void *dev_id)
                                generic_smp_call_function_interrupt();
                                break;
 
-                       case IPI_CALL_FUNC_SINGLE:
-                               smp_debug(100, KERN_DEBUG "CPU%d IPI_CALL_FUNC_SINGLE\n", this_cpu);
-                               generic_smp_call_function_single_interrupt();
-                               break;
-
                        case IPI_CPU_START:
                                smp_debug(100, KERN_DEBUG "CPU%d IPI_CPU_START\n", this_cpu);
                                break;
@@ -260,7 +254,7 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 
 void arch_send_call_function_single_ipi(int cpu)
 {
-       send_IPI_single(cpu, IPI_CALL_FUNC_SINGLE);
+       send_IPI_single(cpu, IPI_CALL_FUNC);
 }
 
 /*
index 04e47c6a45626347aa261d3725005cdafb9385ad..1cd1d0c83b6d7bd7a21d0a22c57e18f2ac27f65a 100644 (file)
@@ -291,11 +291,6 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
        do_exit(SIGSEGV);
 }
 
-int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs)
-{
-       return syscall(regs);
-}
-
 /* gdb uses break 4,8 */
 #define GDB_BREAK_INSN 0x10004
 static void handle_gdb_break(struct pt_regs *regs, int wot)
@@ -805,14 +800,14 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
        else {
 
            /*
-            * The kernel should never fault on its own address space.
+            * The kernel should never fault on its own address space,
+            * unless pagefault_disable() was called before.
             */
 
-           if (fault_space == 0
+           if (fault_space == 0 && !in_atomic())
            {
                pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
                parisc_terminate("Kernel Fault", regs, code, fault_address);
-       
            }
        }
 
index ac4370b1ca4019f5eaf85f910097bf1cc69c0611..b5507ec06b846f09ed4d38c5841b4eecaffb156e 100644 (file)
@@ -56,7 +56,7 @@
 #ifdef __KERNEL__
 #include <linux/module.h>
 #include <linux/compiler.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #define s_space "%%sr1"
 #define d_space "%%sr2"
 #else
@@ -524,4 +524,17 @@ EXPORT_SYMBOL(copy_to_user);
 EXPORT_SYMBOL(copy_from_user);
 EXPORT_SYMBOL(copy_in_user);
 EXPORT_SYMBOL(memcpy);
+
+long probe_kernel_read(void *dst, const void *src, size_t size)
+{
+       unsigned long addr = (unsigned long)src;
+
+       if (size < 0 || addr < PAGE_SIZE)
+               return -EFAULT;
+
+       /* check for I/O space F_EXTEND(0xfff00000) access as well? */
+
+       return __probe_kernel_read(dst, src, size);
+}
+
 #endif
index f247a3480e8e0cd7e276f4fd04004cbb608b3e11..0293588d5b8cb8e2d594406c51bbb524b319888b 100644 (file)
@@ -171,15 +171,27 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
                              unsigned long address)
 {
        struct vm_area_struct *vma, *prev_vma;
-       struct task_struct *tsk = current;
-       struct mm_struct *mm = tsk->mm;
+       struct task_struct *tsk;
+       struct mm_struct *mm;
        unsigned long acc_type;
        int fault;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
+       unsigned int flags;
 
-       if (in_atomic() || !mm)
+       if (in_atomic())
                goto no_context;
 
+       tsk = current;
+       mm = tsk->mm;
+       if (!mm)
+               goto no_context;
+
+       flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
+
+       acc_type = parisc_acctyp(code, regs->iir);
+       if (acc_type & VM_WRITE)
+               flags |= FAULT_FLAG_WRITE;
 retry:
        down_read(&mm->mmap_sem);
        vma = find_vma_prev(mm, address, &prev_vma);
@@ -192,8 +204,6 @@ retry:
 
 good_area:
 
-       acc_type = parisc_acctyp(code,regs->iir);
-
        if ((vma->vm_flags & acc_type) != acc_type)
                goto bad_area;
 
@@ -203,8 +213,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 6a15c968d21453230ab469b5921fea28b790dcc5..15ca2255f43853945789c1fdc58f4a5bc5a82dbf 100644 (file)
@@ -74,7 +74,7 @@ src-wlib-$(CONFIG_8xx) += mpc8xx.c planetcore.c
 src-wlib-$(CONFIG_PPC_82xx) += pq2.c fsl-soc.c planetcore.c
 src-wlib-$(CONFIG_EMBEDDED6xx) += mv64x60.c mv64x60_i2c.c ugecon.c
 
-src-plat-y := of.c
+src-plat-y := of.c epapr.c
 src-plat-$(CONFIG_40x) += fixed-head.S ep405.c cuboot-hotfoot.c \
                                treeboot-walnut.c cuboot-acadia.c \
                                cuboot-kilauea.c simpleboot.c \
@@ -97,7 +97,7 @@ src-plat-$(CONFIG_EMBEDDED6xx) += cuboot-pq2.c cuboot-mpc7448hpc2.c \
                                        prpmc2800.c
 src-plat-$(CONFIG_AMIGAONE) += cuboot-amigaone.c
 src-plat-$(CONFIG_PPC_PS3) += ps3-head.S ps3-hvcall.S ps3.c
-src-plat-$(CONFIG_EPAPR_BOOT) += epapr.c
+src-plat-$(CONFIG_EPAPR_BOOT) += epapr.c epapr-wrapper.c
 
 src-wlib := $(sort $(src-wlib-y))
 src-plat := $(sort $(src-plat-y))
diff --git a/arch/powerpc/boot/epapr-wrapper.c b/arch/powerpc/boot/epapr-wrapper.c
new file mode 100644 (file)
index 0000000..c101910
--- /dev/null
@@ -0,0 +1,9 @@
+extern void epapr_platform_init(unsigned long r3, unsigned long r4,
+                               unsigned long r5, unsigned long r6,
+                               unsigned long r7);
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                  unsigned long r6, unsigned long r7)
+{
+       epapr_platform_init(r3, r4, r5, r6, r7);
+}
index 06c1961bd124a06966da1c5c6a85a6d4452e951a..02e91aa2194a57a66766852444835607143fa29a 100644 (file)
@@ -48,8 +48,8 @@ static void platform_fixups(void)
                       fdt_addr, fdt_totalsize((void *)fdt_addr), ima_size);
 }
 
-void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-                  unsigned long r6, unsigned long r7)
+void epapr_platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                        unsigned long r6, unsigned long r7)
 {
        epapr_magic = r6;
        ima_size = r7;
index 61d9899aa0d09d371c99ec70b7959693f8bfab36..62e2f43ec1df1144d3a790e1f3cf3e3263fdca47 100644 (file)
@@ -26,6 +26,9 @@
 
 static unsigned long claim_base;
 
+void epapr_platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                        unsigned long r6, unsigned long r7);
+
 static void *of_try_claim(unsigned long size)
 {
        unsigned long addr = 0;
@@ -61,7 +64,7 @@ static void of_image_hdr(const void *hdr)
        }
 }
 
-void platform_init(unsigned long a1, unsigned long a2, void *promptr)
+static void of_platform_init(unsigned long a1, unsigned long a2, void *promptr)
 {
        platform_ops.image_hdr = of_image_hdr;
        platform_ops.malloc = of_try_claim;
@@ -81,3 +84,14 @@ void platform_init(unsigned long a1, unsigned long a2, void *promptr)
                loader_info.initrd_size = a2;
        }
 }
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                  unsigned long r6, unsigned long r7)
+{
+       /* Detect OF vs. ePAPR boot */
+       if (r5)
+               of_platform_init(r3, r4, (void *)r5);
+       else
+               epapr_platform_init(r3, r4, r5, r6, r7);
+}
+
index 6761c746048df389812888b8430aca4f442e191c..cd7af841ba051f8725e8ab33dffae1a23201fc60 100755 (executable)
@@ -148,18 +148,18 @@ make_space=y
 
 case "$platform" in
 pseries)
-    platformo=$object/of.o
+    platformo="$object/of.o $object/epapr.o"
     link_address='0x4000000'
     ;;
 maple)
-    platformo=$object/of.o
+    platformo="$object/of.o $object/epapr.o"
     link_address='0x400000'
     ;;
 pmac|chrp)
-    platformo=$object/of.o
+    platformo="$object/of.o $object/epapr.o"
     ;;
 coff)
-    platformo="$object/crt0.o $object/of.o"
+    platformo="$object/crt0.o $object/of.o $object/epapr.o"
     lds=$object/zImage.coff.lds
     link_address='0x500000'
     pie=
@@ -253,6 +253,7 @@ treeboot-iss4xx-mpic)
     platformo="$object/treeboot-iss4xx.o"
     ;;
 epapr)
+    platformo="$object/epapr.o $object/epapr-wrapper.o"
     link_address='0x20000000'
     pie=-pie
     ;;
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 0e40843a1c6ed58273c1a0e2eb22841e9007e977..41f13cec8a8fcd01bbd2e02f3cfc50083b3addba 100644 (file)
@@ -69,9 +69,9 @@ extern struct thread_info *softirq_ctx[NR_CPUS];
 
 extern void irq_ctx_init(void);
 extern void call_do_softirq(struct thread_info *tp);
-extern int call_handle_irq(int irq, void *p1,
-                          struct thread_info *tp, void *func);
+extern void call_do_irq(struct pt_regs *regs, struct thread_info *tp);
 extern void do_IRQ(struct pt_regs *regs);
+extern void __do_irq(struct pt_regs *regs);
 
 int irq_choose_cpu(const struct cpumask *mask);
 
index ae098c438f009eb0e312fc8b78a6ce07f4311cc6..f016bb699b5f6200268d3b8e5bf4e2bd003dbbf7 100644 (file)
@@ -19,7 +19,7 @@
 
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-       asm goto("1:\n\t"
+       asm_volatile_goto("1:\n\t"
                 "nop\n\t"
                 ".pushsection __jump_table,  \"aw\"\n\t"
                 JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t"
index e378cccfca55bb20db094f12a2009ad3ba7bf1a4..ce4de5aed7b5c302b292bd38c69f21bd2f059038 100644 (file)
@@ -149,8 +149,6 @@ typedef struct {
 
 struct thread_struct {
        unsigned long   ksp;            /* Kernel stack pointer */
-       unsigned long   ksp_limit;      /* if ksp <= ksp_limit stack overflow */
-
 #ifdef CONFIG_PPC64
        unsigned long   ksp_vsid;
 #endif
@@ -162,6 +160,7 @@ struct thread_struct {
 #endif
 #ifdef CONFIG_PPC32
        void            *pgdir;         /* root of page-table tree */
+       unsigned long   ksp_limit;      /* if ksp <= ksp_limit stack overflow */
 #endif
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
        /*
@@ -321,7 +320,6 @@ struct thread_struct {
 #else
 #define INIT_THREAD  { \
        .ksp = INIT_SP, \
-       .ksp_limit = INIT_SP_LIMIT, \
        .regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \
        .fs = KERNEL_DS, \
        .fpr = {{0}}, \
index d8958be5f31a18b7c0bae16509749067aae75265..502c7a4e73f70dc1008754b7f55e5ae164f25a76 100644 (file)
@@ -80,10 +80,11 @@ int main(void)
        DEFINE(TASKTHREADPPR, offsetof(struct task_struct, thread.ppr));
 #else
        DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
+       DEFINE(THREAD_INFO_GAP, _ALIGN_UP(sizeof(struct thread_info), 16));
+       DEFINE(KSP_LIMIT, offsetof(struct thread_struct, ksp_limit));
 #endif /* CONFIG_PPC64 */
 
        DEFINE(KSP, offsetof(struct thread_struct, ksp));
-       DEFINE(KSP_LIMIT, offsetof(struct thread_struct, ksp_limit));
        DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
 #ifdef CONFIG_BOOKE
        DEFINE(THREAD_NORMSAVES, offsetof(struct thread_struct, normsave[0]));
index 0adab06ce5c0aaa3e73818951bb4764b047b9a61..572bb5b95f35d815f6f24fe7b59a67bf420fbe2b 100644 (file)
@@ -661,7 +661,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
        /* number of bytes needed for the bitmap */
        sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long);
 
-       page = alloc_pages_node(nid, GFP_ATOMIC, get_order(sz));
+       page = alloc_pages_node(nid, GFP_KERNEL, get_order(sz));
        if (!page)
                panic("iommu_init_table: Can't allocate %ld bytes\n", sz);
        tbl->it_map = page_address(page);
index c69440cef7af43413987f3cd4b2c936cd0e8f788..c7cb8c232d2f4fdedf9129ec691d8471736e2fc7 100644 (file)
@@ -441,50 +441,6 @@ void migrate_irqs(void)
 }
 #endif
 
-static inline void handle_one_irq(unsigned int irq)
-{
-       struct thread_info *curtp, *irqtp;
-       unsigned long saved_sp_limit;
-       struct irq_desc *desc;
-
-       desc = irq_to_desc(irq);
-       if (!desc)
-               return;
-
-       /* Switch to the irq stack to handle this */
-       curtp = current_thread_info();
-       irqtp = hardirq_ctx[smp_processor_id()];
-
-       if (curtp == irqtp) {
-               /* We're already on the irq stack, just handle it */
-               desc->handle_irq(irq, desc);
-               return;
-       }
-
-       saved_sp_limit = current->thread.ksp_limit;
-
-       irqtp->task = curtp->task;
-       irqtp->flags = 0;
-
-       /* Copy the softirq bits in preempt_count so that the
-        * softirq checks work in the hardirq context. */
-       irqtp->preempt_count = (irqtp->preempt_count & ~SOFTIRQ_MASK) |
-                              (curtp->preempt_count & SOFTIRQ_MASK);
-
-       current->thread.ksp_limit = (unsigned long)irqtp +
-               _ALIGN_UP(sizeof(struct thread_info), 16);
-
-       call_handle_irq(irq, desc, irqtp, desc->handle_irq);
-       current->thread.ksp_limit = saved_sp_limit;
-       irqtp->task = NULL;
-
-       /* Set any flag that may have been set on the
-        * alternate stack
-        */
-       if (irqtp->flags)
-               set_bits(irqtp->flags, &curtp->flags);
-}
-
 static inline void check_stack_overflow(void)
 {
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
@@ -501,9 +457,9 @@ static inline void check_stack_overflow(void)
 #endif
 }
 
-void do_IRQ(struct pt_regs *regs)
+void __do_irq(struct pt_regs *regs)
 {
-       struct pt_regs *old_regs = set_irq_regs(regs);
+       struct irq_desc *desc;
        unsigned int irq;
 
        irq_enter();
@@ -519,18 +475,57 @@ void do_IRQ(struct pt_regs *regs)
         */
        irq = ppc_md.get_irq();
 
-       /* We can hard enable interrupts now */
+       /* We can hard enable interrupts now to allow perf interrupts */
        may_hard_irq_enable();
 
        /* And finally process it */
-       if (irq != NO_IRQ)
-               handle_one_irq(irq);
-       else
+       if (unlikely(irq == NO_IRQ))
                __get_cpu_var(irq_stat).spurious_irqs++;
+       else {
+               desc = irq_to_desc(irq);
+               if (likely(desc))
+                       desc->handle_irq(irq, desc);
+       }
 
        trace_irq_exit(regs);
 
        irq_exit();
+}
+
+void do_IRQ(struct pt_regs *regs)
+{
+       struct pt_regs *old_regs = set_irq_regs(regs);
+       struct thread_info *curtp, *irqtp, *sirqtp;
+
+       /* Switch to the irq stack to handle this */
+       curtp = current_thread_info();
+       irqtp = hardirq_ctx[raw_smp_processor_id()];
+       sirqtp = softirq_ctx[raw_smp_processor_id()];
+
+       /* Already there ? */
+       if (unlikely(curtp == irqtp || curtp == sirqtp)) {
+               __do_irq(regs);
+               set_irq_regs(old_regs);
+               return;
+       }
+
+       /* Prepare the thread_info in the irq stack */
+       irqtp->task = curtp->task;
+       irqtp->flags = 0;
+
+       /* Copy the preempt_count so that the [soft]irq checks work. */
+       irqtp->preempt_count = curtp->preempt_count;
+
+       /* Switch stack and call */
+       call_do_irq(regs, irqtp);
+
+       /* Restore stack limit */
+       irqtp->task = NULL;
+
+       /* Copy back updates to the thread_info */
+       if (irqtp->flags)
+               set_bits(irqtp->flags, &curtp->flags);
+
        set_irq_regs(old_regs);
 }
 
@@ -592,28 +587,22 @@ void irq_ctx_init(void)
                memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
                tp = softirq_ctx[i];
                tp->cpu = i;
-               tp->preempt_count = 0;
 
                memset((void *)hardirq_ctx[i], 0, THREAD_SIZE);
                tp = hardirq_ctx[i];
                tp->cpu = i;
-               tp->preempt_count = HARDIRQ_OFFSET;
        }
 }
 
 static inline void do_softirq_onstack(void)
 {
        struct thread_info *curtp, *irqtp;
-       unsigned long saved_sp_limit = current->thread.ksp_limit;
 
        curtp = current_thread_info();
        irqtp = softirq_ctx[smp_processor_id()];
        irqtp->task = curtp->task;
        irqtp->flags = 0;
-       current->thread.ksp_limit = (unsigned long)irqtp +
-                                   _ALIGN_UP(sizeof(struct thread_info), 16);
        call_do_softirq(irqtp);
-       current->thread.ksp_limit = saved_sp_limit;
        irqtp->task = NULL;
 
        /* Set any flag that may have been set on the
index 777d999f563bb377bff3217358aacdc7667f1fd4..2b0ad984536333d7a15a3b39e6c9234c11b4b669 100644 (file)
 
        .text
 
+/*
+ * We store the saved ksp_limit in the unused part
+ * of the STACK_FRAME_OVERHEAD
+ */
 _GLOBAL(call_do_softirq)
        mflr    r0
        stw     r0,4(r1)
+       lwz     r10,THREAD+KSP_LIMIT(r2)
+       addi    r11,r3,THREAD_INFO_GAP
        stwu    r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
        mr      r1,r3
+       stw     r10,8(r1)
+       stw     r11,THREAD+KSP_LIMIT(r2)
        bl      __do_softirq
+       lwz     r10,8(r1)
        lwz     r1,0(r1)
        lwz     r0,4(r1)
+       stw     r10,THREAD+KSP_LIMIT(r2)
        mtlr    r0
        blr
 
-_GLOBAL(call_handle_irq)
+_GLOBAL(call_do_irq)
        mflr    r0
        stw     r0,4(r1)
-       mtctr   r6
-       stwu    r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r5)
-       mr      r1,r5
-       bctrl
+       lwz     r10,THREAD+KSP_LIMIT(r2)
+       addi    r11,r3,THREAD_INFO_GAP
+       stwu    r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
+       mr      r1,r4
+       stw     r10,8(r1)
+       stw     r11,THREAD+KSP_LIMIT(r2)
+       bl      __do_irq
+       lwz     r10,8(r1)
        lwz     r1,0(r1)
        lwz     r0,4(r1)
+       stw     r10,THREAD+KSP_LIMIT(r2)
        mtlr    r0
        blr
 
index 971d7e78aff20e1ca801dd923dfc77337e834ad5..e59caf874d05ed60e500579b06bfcdf38bd85125 100644 (file)
@@ -40,14 +40,12 @@ _GLOBAL(call_do_softirq)
        mtlr    r0
        blr
 
-_GLOBAL(call_handle_irq)
-       ld      r8,0(r6)
+_GLOBAL(call_do_irq)
        mflr    r0
        std     r0,16(r1)
-       mtctr   r8
-       stdu    r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r5)
-       mr      r1,r5
-       bctrl
+       stdu    r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
+       mr      r1,r4
+       bl      .__do_irq
        ld      r1,0(r1)
        ld      r0,16(r1)
        mtlr    r0
index 6f428da53e2085b877334270286069e2ba54da37..96d2fdf3aa9ebe3bba547fd567c5a232be20ec9a 100644 (file)
@@ -1000,9 +1000,10 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        kregs = (struct pt_regs *) sp;
        sp -= STACK_FRAME_OVERHEAD;
        p->thread.ksp = sp;
+#ifdef CONFIG_PPC32
        p->thread.ksp_limit = (unsigned long)task_stack_page(p) +
                                _ALIGN_UP(sizeof(struct thread_info), 16);
-
+#endif
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
        p->thread.ptrace_bps[0] = NULL;
 #endif
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..5fe2842e8bab7cc4013c987c74791c00005c51ee 100644 (file)
@@ -196,6 +196,8 @@ static int __initdata mem_reserve_cnt;
 
 static cell_t __initdata regbuf[1024];
 
+static bool rtas_has_query_cpu_stopped;
+
 
 /*
  * Error results ... some OF calls will return "-1" on error, some
@@ -1297,7 +1299,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;
@@ -1573,6 +1576,11 @@ static void __init prom_instantiate_rtas(void)
        prom_setprop(rtas_node, "/rtas", "linux,rtas-entry",
                     &val, sizeof(val));
 
+       /* Check if it supports "query-cpu-stopped-state" */
+       if (prom_getprop(rtas_node, "query-cpu-stopped-state",
+                        &val, sizeof(val)) != PROM_ERROR)
+               rtas_has_query_cpu_stopped = true;
+
 #if defined(CONFIG_PPC_POWERNV) && defined(__BIG_ENDIAN__)
        /* PowerVN takeover hack */
        prom_rtas_data = base;
@@ -1814,6 +1822,18 @@ static void __init prom_hold_cpus(void)
                = (void *) LOW_ADDR(__secondary_hold_acknowledge);
        unsigned long secondary_hold = LOW_ADDR(__secondary_hold);
 
+       /*
+        * On pseries, if RTAS supports "query-cpu-stopped-state",
+        * we skip this stage, the CPUs will be started by the
+        * kernel using RTAS.
+        */
+       if ((of_platform == PLATFORM_PSERIES ||
+            of_platform == PLATFORM_PSERIES_LPAR) &&
+           rtas_has_query_cpu_stopped) {
+               prom_printf("prom_hold_cpus: skipped\n");
+               return;
+       }
+
        prom_debug("prom_hold_cpus: start...\n");
        prom_debug("    1) spinloop       = 0x%x\n", (unsigned long)spinloop);
        prom_debug("    1) *spinloop      = 0x%x\n", *spinloop);
@@ -3010,6 +3030,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
         * On non-powermacs, put all CPUs in spin-loops.
         *
         * PowerMacs use a different mechanism to spin CPUs
+        *
+        * (This must be done after instanciating RTAS)
         */
        if (of_platform != PLATFORM_POWERMAC &&
            of_platform != PLATFORM_OPAL)
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 27a90b99ef6744d20fa6664bb1c6244626a5cd0d..b4e667663d9bfc2e9954435790b0ebc5b6fc94ca 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/machdep.h>
 #include <asm/smp.h>
 #include <asm/pmc.h>
+#include <asm/firmware.h>
 
 #include "cacheinfo.h"
 
@@ -179,15 +180,25 @@ SYSFS_PMCSETUP(spurr, SPRN_SPURR);
 SYSFS_PMCSETUP(dscr, SPRN_DSCR);
 SYSFS_PMCSETUP(pir, SPRN_PIR);
 
+/*
+  Lets only enable read for phyp resources and
+  enable write when needed with a separate function.
+  Lets be conservative and default to pseries.
+*/
 static DEVICE_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
 static DEVICE_ATTR(spurr, 0400, show_spurr, NULL);
 static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr);
-static DEVICE_ATTR(purr, 0600, show_purr, store_purr);
+static DEVICE_ATTR(purr, 0400, show_purr, store_purr);
 static DEVICE_ATTR(pir, 0400, show_pir, NULL);
 
 unsigned long dscr_default = 0;
 EXPORT_SYMBOL(dscr_default);
 
+static void add_write_permission_dev_attr(struct device_attribute *attr)
+{
+       attr->attr.mode |= 0200;
+}
+
 static ssize_t show_dscr_default(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -394,8 +405,11 @@ static void register_cpu_online(unsigned int cpu)
        if (cpu_has_feature(CPU_FTR_MMCRA))
                device_create_file(s, &dev_attr_mmcra);
 
-       if (cpu_has_feature(CPU_FTR_PURR))
+       if (cpu_has_feature(CPU_FTR_PURR)) {
+               if (!firmware_has_feature(FW_FEATURE_LPAR))
+                       add_write_permission_dev_attr(&dev_attr_purr);
                device_create_file(s, &dev_attr_purr);
+       }
 
        if (cpu_has_feature(CPU_FTR_SPURR))
                device_create_file(s, &dev_attr_spurr);
index 7b60b98514691ee554d1140e408c9802f83d21a4..cd809eaa8b5c4bec7d00497e0edaa614501f13e0 100644 (file)
@@ -79,6 +79,11 @@ _GLOBAL(tm_abort)
        TABORT(R3)
        blr
 
+       .section        ".toc","aw"
+DSCR_DEFAULT:
+       .tc dscr_default[TC],dscr_default
+
+       .section        ".text"
 
 /* void tm_reclaim(struct thread_struct *thread,
  *                 unsigned long orig_msr,
@@ -123,6 +128,7 @@ _GLOBAL(tm_reclaim)
        mr      r15, r14
        ori     r15, r15, MSR_FP
        li      r16, MSR_RI
+       ori     r16, r16, MSR_EE /* IRQs hard off */
        andc    r15, r15, r16
        oris    r15, r15, MSR_VEC@h
 #ifdef CONFIG_VSX
@@ -187,11 +193,18 @@ dont_backup_fp:
        std     r1, PACATMSCRATCH(r13)
        ld      r1, PACAR1(r13)
 
+       /* Store the PPR in r11 and reset to decent value */
+       std     r11, GPR11(r1)                  /* Temporary stash */
+       mfspr   r11, SPRN_PPR
+       HMT_MEDIUM
+
        /* Now get some more GPRS free */
        std     r7, GPR7(r1)                    /* Temporary stash */
        std     r12, GPR12(r1)                  /* ''   ''    ''   */
        ld      r12, STACK_PARAM(0)(r1)         /* Param 0, thread_struct * */
 
+       std     r11, THREAD_TM_PPR(r12)         /* Store PPR and free r11 */
+
        addi    r7, r12, PT_CKPT_REGS           /* Thread's ckpt_regs */
 
        /* Make r7 look like an exception frame so that we
@@ -203,15 +216,19 @@ dont_backup_fp:
        SAVE_GPR(0, r7)                         /* user r0 */
        SAVE_GPR(2, r7)                 /* user r2 */
        SAVE_4GPRS(3, r7)                       /* user r3-r6 */
-       SAVE_4GPRS(8, r7)                       /* user r8-r11 */
+       SAVE_GPR(8, r7)                         /* user r8 */
+       SAVE_GPR(9, r7)                         /* user r9 */
+       SAVE_GPR(10, r7)                        /* user r10 */
        ld      r3, PACATMSCRATCH(r13)          /* user r1 */
        ld      r4, GPR7(r1)                    /* user r7 */
-       ld      r5, GPR12(r1)                   /* user r12 */
-       GET_SCRATCH0(6)                         /* user r13 */
+       ld      r5, GPR11(r1)                   /* user r11 */
+       ld      r6, GPR12(r1)                   /* user r12 */
+       GET_SCRATCH0(8)                         /* user r13 */
        std     r3, GPR1(r7)
        std     r4, GPR7(r7)
-       std     r5, GPR12(r7)
-       std     r6, GPR13(r7)
+       std     r5, GPR11(r7)
+       std     r6, GPR12(r7)
+       std     r8, GPR13(r7)
 
        SAVE_NVGPRS(r7)                         /* user r14-r31 */
 
@@ -234,14 +251,12 @@ dont_backup_fp:
        std     r6, _XER(r7)
 
 
-       /* ******************** TAR, PPR, DSCR ********** */
+       /* ******************** TAR, DSCR ********** */
        mfspr   r3, SPRN_TAR
-       mfspr   r4, SPRN_PPR
-       mfspr   r5, SPRN_DSCR
+       mfspr   r4, SPRN_DSCR
 
        std     r3, THREAD_TM_TAR(r12)
-       std     r4, THREAD_TM_PPR(r12)
-       std     r5, THREAD_TM_DSCR(r12)
+       std     r4, THREAD_TM_DSCR(r12)
 
        /* MSR and flags:  We don't change CRs, and we don't need to alter
         * MSR.
@@ -258,7 +273,7 @@ dont_backup_fp:
        std     r3, THREAD_TM_TFHAR(r12)
        std     r4, THREAD_TM_TFIAR(r12)
 
-       /* AMR and PPR are checkpointed too, but are unsupported by Linux. */
+       /* AMR is checkpointed too, but is unsupported by Linux. */
 
        /* Restore original MSR/IRQ state & clear TM mode */
        ld      r14, TM_FRAME_L0(r1)            /* Orig MSR */
@@ -274,6 +289,12 @@ dont_backup_fp:
        mtcr    r4
        mtlr    r0
        ld      r2, 40(r1)
+
+       /* Load system default DSCR */
+       ld      r4, DSCR_DEFAULT@toc(r2)
+       ld      r0, 0(r4)
+       mtspr   SPRN_DSCR, r0
+
        blr
 
 
@@ -358,25 +379,24 @@ dont_restore_fp:
 
 restore_gprs:
 
-       /* ******************** TAR, PPR, DSCR ********** */
-       ld      r4, THREAD_TM_TAR(r3)
-       ld      r5, THREAD_TM_PPR(r3)
-       ld      r6, THREAD_TM_DSCR(r3)
+       /* ******************** CR,LR,CCR,MSR ********** */
+       ld      r4, _CTR(r7)
+       ld      r5, _LINK(r7)
+       ld      r6, _CCR(r7)
+       ld      r8, _XER(r7)
 
-       mtspr   SPRN_TAR,       r4
-       mtspr   SPRN_PPR,       r5
-       mtspr   SPRN_DSCR,      r6
+       mtctr   r4
+       mtlr    r5
+       mtcr    r6
+       mtxer   r8
 
-       /* ******************** CR,LR,CCR,MSR ********** */
-       ld      r3, _CTR(r7)
-       ld      r4, _LINK(r7)
-       ld      r5, _CCR(r7)
-       ld      r6, _XER(r7)
+       /* ******************** TAR ******************** */
+       ld      r4, THREAD_TM_TAR(r3)
+       mtspr   SPRN_TAR,       r4
 
-       mtctr   r3
-       mtlr    r4
-       mtcr    r5
-       mtxer   r6
+       /* Load up the PPR and DSCR in GPRs only at this stage */
+       ld      r5, THREAD_TM_DSCR(r3)
+       ld      r6, THREAD_TM_PPR(r3)
 
        /* Clear the MSR RI since we are about to change R1.  EE is already off
         */
@@ -384,19 +404,26 @@ restore_gprs:
        mtmsrd  r4, 1
 
        REST_4GPRS(0, r7)                       /* GPR0-3 */
-       REST_GPR(4, r7)                         /* GPR4-6 */
-       REST_GPR(5, r7)
-       REST_GPR(6, r7)
+       REST_GPR(4, r7)                         /* GPR4 */
        REST_4GPRS(8, r7)                       /* GPR8-11 */
        REST_2GPRS(12, r7)                      /* GPR12-13 */
 
        REST_NVGPRS(r7)                         /* GPR14-31 */
 
-       ld      r7, GPR7(r7)                    /* GPR7 */
+       /* Load up PPR and DSCR here so we don't run with user values for long
+        */
+       mtspr   SPRN_DSCR, r5
+       mtspr   SPRN_PPR, r6
+
+       REST_GPR(5, r7)                         /* GPR5-7 */
+       REST_GPR(6, r7)
+       ld      r7, GPR7(r7)
 
        /* Commit register state as checkpointed state: */
        TRECHKPT
 
+       HMT_MEDIUM
+
        /* Our transactional state has now changed.
         *
         * Now just get out of here.  Transactional (current) state will be
@@ -419,6 +446,12 @@ restore_gprs:
        mtcr    r4
        mtlr    r0
        ld      r2, 40(r1)
+
+       /* Load system default DSCR */
+       ld      r4, DSCR_DEFAULT@toc(r2)
+       ld      r0, 0(r4)
+       mtspr   SPRN_DSCR, r0
+
        blr
 
        /* ****************************************************************** */
index 78a350670de32b4ba7013ea8fefe2ab5c0d5d626..d38cc08b16c7f23831e3af558bfe35908e14af47 100644 (file)
@@ -1530,11 +1530,15 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
        const char *cp;
 
        dn = dev->of_node;
-       if (!dn)
-               return -ENODEV;
+       if (!dn) {
+               strcat(buf, "\n");
+               return strlen(buf);
+       }
        cp = of_get_property(dn, "compatible", NULL);
-       if (!cp)
-               return -ENODEV;
+       if (!cp) {
+               strcat(buf, "\n");
+               return strlen(buf);
+       }
 
        return sprintf(buf, "vio:T%sS%s\n", vio_dev->type, cp);
 }
index 294b7af28cdd3c58b2551c53b9210daa429f836d..c71103b8a748350947ad3c2f6b7256c6c2841405 100644 (file)
@@ -1066,7 +1066,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 BEGIN_FTR_SECTION
        mfspr   r8, SPRN_DSCR
        ld      r7, HSTATE_DSCR(r13)
-       std     r8, VCPU_DSCR(r7)
+       std     r8, VCPU_DSCR(r9)
        mtspr   SPRN_DSCR, r7
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 
index 1c6a9d729df4a26ca3ad6c9f1c94008d681f7d42..c65593abae8eb879f71915cbf639f0dfec4468dc 100644 (file)
@@ -332,6 +332,13 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
        unsigned long hva;
        int pfnmap = 0;
        int tsize = BOOK3E_PAGESZ_4K;
+       int ret = 0;
+       unsigned long mmu_seq;
+       struct kvm *kvm = vcpu_e500->vcpu.kvm;
+
+       /* used to check for invalidations in progress */
+       mmu_seq = kvm->mmu_notifier_seq;
+       smp_rmb();
 
        /*
         * Translate guest physical to true physical, acquiring
@@ -449,6 +456,12 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
                gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
        }
 
+       spin_lock(&kvm->mmu_lock);
+       if (mmu_notifier_retry(kvm, mmu_seq)) {
+               ret = -EAGAIN;
+               goto out;
+       }
+
        kvmppc_e500_ref_setup(ref, gtlbe, pfn);
 
        kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize,
@@ -457,10 +470,13 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
        /* Clear i-cache for new pages */
        kvmppc_mmu_flush_icache(pfn);
 
+out:
+       spin_unlock(&kvm->mmu_lock);
+
        /* Drop refcount on page, so that mmu notifiers can clear it */
        kvm_release_pfn_clean(pfn);
 
-       return 0;
+       return ret;
 }
 
 /* XXX only map the one-one case, for now use TLB0 */
index 167f72555d604dc6c24194e3bb9c1e0b3d021bc4..57a0720650576a9f72e98cece18a71e25045ec3a 100644 (file)
@@ -226,19 +226,35 @@ _GLOBAL(csum_partial)
        blr
 
 
-       .macro source
+       .macro srcnr
 100:
        .section __ex_table,"a"
        .align 3
-       .llong 100b,.Lsrc_error
+       .llong 100b,.Lsrc_error_nr
        .previous
        .endm
 
-       .macro dest
+       .macro source
+150:
+       .section __ex_table,"a"
+       .align 3
+       .llong 150b,.Lsrc_error
+       .previous
+       .endm
+
+       .macro dstnr
 200:
        .section __ex_table,"a"
        .align 3
-       .llong 200b,.Ldest_error
+       .llong 200b,.Ldest_error_nr
+       .previous
+       .endm
+
+       .macro dest
+250:
+       .section __ex_table,"a"
+       .align 3
+       .llong 250b,.Ldest_error
        .previous
        .endm
 
@@ -269,16 +285,16 @@ _GLOBAL(csum_partial_copy_generic)
        rldicl. r6,r3,64-1,64-2         /* r6 = (r3 & 0x3) >> 1 */
        beq     .Lcopy_aligned
 
-       li      r7,4
-       sub     r6,r7,r6
+       li      r9,4
+       sub     r6,r9,r6
        mtctr   r6
 
 1:
-source;        lhz     r6,0(r3)                /* align to doubleword */
+srcnr; lhz     r6,0(r3)                /* align to doubleword */
        subi    r5,r5,2
        addi    r3,r3,2
        adde    r0,r0,r6
-dest;  sth     r6,0(r4)
+dstnr; sth     r6,0(r4)
        addi    r4,r4,2
        bdnz    1b
 
@@ -392,10 +408,10 @@ dest;     std     r16,56(r4)
 
        mtctr   r6
 3:
-source;        ld      r6,0(r3)
+srcnr; ld      r6,0(r3)
        addi    r3,r3,8
        adde    r0,r0,r6
-dest;  std     r6,0(r4)
+dstnr; std     r6,0(r4)
        addi    r4,r4,8
        bdnz    3b
 
@@ -405,10 +421,10 @@ dest;     std     r6,0(r4)
        srdi.   r6,r5,2
        beq     .Lcopy_tail_halfword
 
-source;        lwz     r6,0(r3)
+srcnr; lwz     r6,0(r3)
        addi    r3,r3,4
        adde    r0,r0,r6
-dest;  stw     r6,0(r4)
+dstnr; stw     r6,0(r4)
        addi    r4,r4,4
        subi    r5,r5,4
 
@@ -416,10 +432,10 @@ dest;     stw     r6,0(r4)
        srdi.   r6,r5,1
        beq     .Lcopy_tail_byte
 
-source;        lhz     r6,0(r3)
+srcnr; lhz     r6,0(r3)
        addi    r3,r3,2
        adde    r0,r0,r6
-dest;  sth     r6,0(r4)
+dstnr; sth     r6,0(r4)
        addi    r4,r4,2
        subi    r5,r5,2
 
@@ -427,10 +443,10 @@ dest;     sth     r6,0(r4)
        andi.   r6,r5,1
        beq     .Lcopy_finish
 
-source;        lbz     r6,0(r3)
+srcnr; lbz     r6,0(r3)
        sldi    r9,r6,8                 /* Pad the byte out to 16 bits */
        adde    r0,r0,r9
-dest;  stb     r6,0(r4)
+dstnr; stb     r6,0(r4)
 
 .Lcopy_finish:
        addze   r0,r0                   /* add in final carry */
@@ -440,6 +456,11 @@ dest;      stb     r6,0(r4)
        blr
 
 .Lsrc_error:
+       ld      r14,STK_REG(R14)(r1)
+       ld      r15,STK_REG(R15)(r1)
+       ld      r16,STK_REG(R16)(r1)
+       addi    r1,r1,STACKFRAMESIZE
+.Lsrc_error_nr:
        cmpdi   0,r7,0
        beqlr
        li      r6,-EFAULT
@@ -447,6 +468,11 @@ dest;      stb     r6,0(r4)
        blr
 
 .Ldest_error:
+       ld      r14,STK_REG(R14)(r1)
+       ld      r15,STK_REG(R15)(r1)
+       ld      r16,STK_REG(R16)(r1)
+       addi    r1,r1,STACKFRAMESIZE
+.Ldest_error_nr:
        cmpdi   0,r8,0
        beqlr
        li      r6,-EFAULT
index a7ee978fb860c9ffd237d9fbafb716b724e3afec..b1faa1593c9067e68995e1cdc54dbb8465dce587 100644 (file)
@@ -1505,6 +1505,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                 */
                if ((ra == 1) && !(regs->msr & MSR_PR) \
                        && (val3 >= (regs->gpr[1] - STACK_INT_FRAME_SIZE))) {
+#ifdef CONFIG_PPC32
                        /*
                         * Check if we will touch kernel sack overflow
                         */
@@ -1513,7 +1514,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                                err = -EINVAL;
                                break;
                        }
-
+#endif /* CONFIG_PPC32 */
                        /*
                         * Check if we already set since that means we'll
                         * lose the previous value.
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 d0cd9e4c6837d2d17620b0f646151d9a54408f71..8ed035d2edb5a51540d580e4b6a6a5a106b3a5f9 100644 (file)
@@ -300,5 +300,9 @@ void vmemmap_free(unsigned long start, unsigned long end)
 {
 }
 
+void register_page_bootmem_memmap(unsigned long section_nr,
+                                 struct page *start_page, unsigned long size)
+{
+}
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
index 1cf9c5b67f241f40f46b127024c4a659e95af221..3fa93dc7fe750a9f53c875493b969f1962bea9af 100644 (file)
@@ -297,12 +297,21 @@ void __init paging_init(void)
 }
 #endif /* ! CONFIG_NEED_MULTIPLE_NODES */
 
+static void __init register_page_bootmem_info(void)
+{
+       int i;
+
+       for_each_online_node(i)
+               register_page_bootmem_info_node(NODE_DATA(i));
+}
+
 void __init mem_init(void)
 {
 #ifdef CONFIG_SWIOTLB
        swiotlb_init(0);
 #endif
 
+       register_page_bootmem_info();
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
        set_max_mapnr(max_pfn);
        free_all_bootmem();
index 2ee4a707f0df85c37dba15c6ab5f4e7f84e553fc..a3f7abd2f13f7a0793ce4e2bdb00855f9724d108 100644 (file)
 #define MMCR1_UNIT_SHIFT(pmc)          (60 - (4 * ((pmc) - 1)))
 #define MMCR1_COMBINE_SHIFT(pmc)       (35 - ((pmc) - 1))
 #define MMCR1_PMCSEL_SHIFT(pmc)                (24 - (((pmc) - 1)) * 8)
+#define MMCR1_FAB_SHIFT                        36
 #define MMCR1_DC_QUAL_SHIFT            47
 #define MMCR1_IC_QUAL_SHIFT            46
 
@@ -388,8 +389,8 @@ static int power8_compute_mmcr(u64 event[], int n_ev,
                 * the threshold bits are used for the match value.
                 */
                if (event_is_fab_match(event[i])) {
-                       mmcr1 |= (event[i] >> EVENT_THR_CTL_SHIFT) &
-                                 EVENT_THR_CTL_MASK;
+                       mmcr1 |= ((event[i] >> EVENT_THR_CTL_SHIFT) &
+                                 EVENT_THR_CTL_MASK) << MMCR1_FAB_SHIFT;
                } else {
                        val = (event[i] >> EVENT_THR_CTL_SHIFT) & EVENT_THR_CTL_MASK;
                        mmcra |= val << MMCRA_THR_CTL_SHIFT;
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 1c1771a402501d00328c450cfaeb5942f360d3f4..24f58cb0a543ece1cb92242b36ec8e18c145f5be 100644 (file)
@@ -233,18 +233,24 @@ static void __init smp_init_pseries(void)
 
        alloc_bootmem_cpumask_var(&of_spin_mask);
 
-       /* Mark threads which are still spinning in hold loops. */
-       if (cpu_has_feature(CPU_FTR_SMT)) {
-               for_each_present_cpu(i) { 
-                       if (cpu_thread_in_core(i) == 0)
-                               cpumask_set_cpu(i, of_spin_mask);
-               }
-       } else {
-               cpumask_copy(of_spin_mask, cpu_present_mask);
+       /*
+        * Mark threads which are still spinning in hold loops
+        *
+        * We know prom_init will not have started them if RTAS supports
+        * query-cpu-stopped-state.
+        */
+       if (rtas_token("query-cpu-stopped-state") == RTAS_UNKNOWN_SERVICE) {
+               if (cpu_has_feature(CPU_FTR_SMT)) {
+                       for_each_present_cpu(i) {
+                               if (cpu_thread_in_core(i) == 0)
+                                       cpumask_set_cpu(i, of_spin_mask);
+                       }
+               } else
+                       cpumask_copy(of_spin_mask, cpu_present_mask);
+
+               cpumask_clear_cpu(boot_cpuid, of_spin_mask);
        }
 
-       cpumask_clear_cpu(boot_cpuid, of_spin_mask);
-
        /* Non-lpar has additional take/give timebase */
        if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
                smp_ops->give_timebase = rtas_give_timebase;
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..7143793859fadf0cbc66c1b2119c5cbaee6368c8 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,8 +92,8 @@ 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_USE_CMPXCHG_LOCKREF
        select ARCH_WANT_IPC_PARSE_VERSION
        select BUILDTIME_EXTABLE_SORT
        select CLONE_BACKWARDS2
@@ -102,7 +103,6 @@ config S390
        select GENERIC_TIME_VSYSCALL_OLD
        select HAVE_ALIGNED_STRUCT_PAGE if SLUB
        select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
-       select HAVE_ARCH_MUTEX_CPU_RELAX
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE if 64BIT
@@ -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 6c32190dc73e880255175049fe36965e647101eb..346b1c85ffb40d890078550dc72c2dedcb275a2e 100644 (file)
@@ -15,7 +15,7 @@
 
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-       asm goto("0:    brcl 0,0\n"
+       asm_volatile_goto("0:   brcl 0,0\n"
                ".pushsection __jump_table, \"aw\"\n"
                ASM_ALIGN "\n"
                ASM_PTR " 0b, %l[label], %0\n"
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 688271f5f2e452b9951599550f33ed0ddcfe0a7c..458c1f7fbc1808d48982aa0c5fe89bfe3df2098c 100644 (file)
@@ -7,5 +7,3 @@
  */
 
 #include <asm-generic/mutex-dec.h>
-
-#define arch_mutex_cpu_relax() barrier()
index 0eb37505cab11c71f083ed508f02c98a72127e95..ca7821f07260301f26c2ff9314432b193ad8bebf 100644 (file)
@@ -198,6 +198,8 @@ static inline void cpu_relax(void)
        barrier();
 }
 
+#define arch_mutex_cpu_relax()  barrier()
+
 static inline void psw_set_key(unsigned int key)
 {
        asm volatile("spka 0(%0)" : : "d" (key));
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 701fe8c59e1f0e9efc302e711eef5bcfe3db479a..83e5d216105e86a2df2ab1367bcfc3fd1590542a 100644 (file)
@@ -44,6 +44,11 @@ extern void arch_spin_lock_wait_flags(arch_spinlock_t *, unsigned long flags);
 extern int arch_spin_trylock_retry(arch_spinlock_t *);
 extern void arch_spin_relax(arch_spinlock_t *lock);
 
+static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
+{
+       return lock.owner_cpu == 0;
+}
+
 static inline void arch_spin_lock(arch_spinlock_t *lp)
 {
        int old;
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..7dd21720e5b002d03ff406afb12faf546f09e9f3 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)))
@@ -39,47 +40,69 @@ static inline void *load_real_addr(void *addr)
 }
 
 /*
- * Copy up to one page to vmalloc or real memory
+ * Copy real to virtual or real memory
  */
-static ssize_t copy_page_real(void *buf, void *src, size_t csize)
+static int copy_from_realmem(void *dest, void *src, size_t count)
 {
-       size_t size;
+       unsigned long size;
+       int rc;
 
-       if (is_vmalloc_addr(buf)) {
-               BUG_ON(csize >= PAGE_SIZE);
-               /* If buf is not page aligned, copy first part */
-               size = min(roundup(__pa(buf), PAGE_SIZE) - __pa(buf), csize);
-               if (size) {
-                       if (memcpy_real(load_real_addr(buf), src, size))
-                               return -EFAULT;
-                       buf += size;
-                       src += size;
-               }
-               /* Copy second part */
-               size = csize - size;
-               return (size) ? memcpy_real(load_real_addr(buf), src, size) : 0;
+       if (!count)
+               return 0;
+       if (!is_vmalloc_or_module_addr(dest))
+               return memcpy_real(dest, src, count);
+       do {
+               size = min(count, PAGE_SIZE - (__pa(dest) & ~PAGE_MASK));
+               if (memcpy_real(load_real_addr(dest), src, size))
+                       return -EFAULT;
+               count -= size;
+               dest += size;
+               src += size;
+       } while (count);
+       return 0;
+}
+
+/*
+ * 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 {
-               return memcpy_real(buf, src, csize);
+               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 "oldmem"
+ * 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 &&
@@ -89,8 +112,89 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
                rc = copy_to_user_real((void __force __user *) buf,
                                       (void *) src, csize);
        else
-               rc = copy_page_real(buf, (void *) src, csize);
-       return (rc == 0) ? csize : rc;
+               rc = copy_from_realmem(buf, (void *) src, csize);
+       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,13 +205,23 @@ 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 = copy_from_realmem(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);
+       return copy_from_realmem(dest + copied, src + copied, count - copied);
 }
 
 /*
@@ -367,14 +481,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 +532,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 +541,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 +549,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 +572,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 cc30d1fb000c25c8f74a8045b105762ccf32c9b2..0dc2b6d0a1ec8557f7450d5fbd255d2758bf8512 100644 (file)
@@ -266,6 +266,7 @@ sysc_sigpending:
        tm      __TI_flags+3(%r12),_TIF_SYSCALL
        jno     sysc_return
        lm      %r2,%r7,__PT_R2(%r11)   # load svc arguments
+       l       %r10,__TI_sysc_table(%r12)      # 31 bit system call table
        xr      %r8,%r8                 # svc 0 returns -ENOSYS
        clc     __PT_INT_CODE+2(2,%r11),BASED(.Lnr_syscalls+2)
        jnl     sysc_nr_ok              # invalid svc number -> do svc 0
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 2b2188b97c6aff464e467b7250823257924e31ab..e5b43c97a8340a807671ace329a4fa87a573709a 100644 (file)
@@ -297,6 +297,7 @@ sysc_sigpending:
        tm      __TI_flags+7(%r12),_TIF_SYSCALL
        jno     sysc_return
        lmg     %r2,%r7,__PT_R2(%r11)   # load svc arguments
+       lg      %r10,__TI_sysc_table(%r12)      # address of system call table
        lghi    %r8,0                   # svc 0 returns -ENOSYS
        llgh    %r1,__PT_INT_CODE+2(%r11)       # load new svc number
        cghi    %r1,NR_syscalls
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..d86e64eddb42efdedf44078cc8e29a51247eba87 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) {
@@ -47,6 +67,11 @@ static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn)
        case 0xac:      /* stnsm */
        case 0xad:      /* stosm */
                return -EINVAL;
+       case 0xc6:
+               switch (insn[0] & 0x0f) {
+               case 0x00: /* exrl   */
+                       return -EINVAL;
+               }
        }
        switch (insn[0]) {
        case 0x0101:    /* pr    */
@@ -100,9 +125,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 +158,127 @@ 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 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 +319,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..305f7ee1f382e60739464c6d0f3de98855d638ea 100644 (file)
@@ -111,3 +111,6 @@ source "security/Kconfig"
 source "crypto/Kconfig"
 
 source "lib/Kconfig"
+
+config NO_IOMEM
+       def_bool y
index 974aefe861233b8615ed61253a6f7a1d4b21085c..9e3e060290e0895529c864d7e6892e0c47708f43 100644 (file)
@@ -20,8 +20,8 @@ cflags-y += -G0 -pipe -mel -mnhwloop -D__SCOREEL__ \
 #
 KBUILD_AFLAGS += $(cflags-y)
 KBUILD_CFLAGS += $(cflags-y)
-KBUILD_AFLAGS_MODULE += -mlong-calls
-KBUILD_CFLAGS_MODULE += -mlong-calls
+KBUILD_AFLAGS_MODULE +=
+KBUILD_CFLAGS_MODULE +=
 LDFLAGS += --oformat elf32-littlescore
 LDFLAGS_vmlinux        += -G0 -static -nostdlib
 
index f909ac3144a45a895751d038fbfea7495be59898..961bd64015a817b50452499d992ce23f14291247 100644 (file)
@@ -184,48 +184,57 @@ static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
                                __wsum sum)
 {
        __asm__ __volatile__(
-               ".set\tnoreorder\t\t\t# csum_ipv6_magic\n\t"
-               ".set\tnoat\n\t"
-               "addu\t%0, %5\t\t\t# proto (long in network byte order)\n\t"
-               "sltu\t$1, %0, %5\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %6\t\t\t# csum\n\t"
-               "sltu\t$1, %0, %6\n\t"
-               "lw\t%1, 0(%2)\t\t\t# four words source address\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 4(%2)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 8(%2)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 12(%2)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 0(%3)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 4(%3)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 8(%3)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "lw\t%1, 12(%3)\n\t"
-               "addu\t%0, $1\n\t"
-               "addu\t%0, %1\n\t"
-               "sltu\t$1, %0, %1\n\t"
-               "addu\t%0, $1\t\t\t# Add final carry\n\t"
-               ".set\tnoat\n\t"
-               ".set\tnoreorder"
+               ".set\tvolatile\t\t\t# csum_ipv6_magic\n\t"
+               "add\t%0, %0, %5\t\t\t# proto (long in network byte order)\n\t"
+               "cmp.c\t%5, %0\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %6\t\t\t# csum\n\t"
+               "cmp.c\t%6, %0\n\t"
+               "lw\t%1, [%2, 0]\t\t\t# four words source address\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "1:lw\t%1, [%2, 4]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "lw\t%1, [%2,8]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "lw\t%1, [%2, 12]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0,%1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "lw\t%1, [%3, 0]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "lw\t%1, [%3, 4]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "lw\t%1, [%3, 8]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "lw\t%1, [%3, 12]\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:add\t%0, %0, %1\n\t"
+               "cmp.c\t%1, %0\n\t"
+               "bleu 1f\n\t"
+               "addi\t%0, 0x1\n\t"
+               "1:\n\t"
+               ".set\toptimize"
                : "=r" (sum), "=r" (proto)
                : "r" (saddr), "r" (daddr),
                  "0" (htonl(len)), "1" (htonl(proto)), "r" (sum));
index fbbfd7132e3b30b6d338fec1f9ea8f7572a76d7d..574c8827abe2381f2db65dfaf3a8f889cf52987b 100644 (file)
@@ -5,5 +5,4 @@
 
 #define virt_to_bus    virt_to_phys
 #define bus_to_virt    phys_to_virt
-
 #endif /* _ASM_SCORE_IO_H */
index 059a61b7071b2ab4d8e5ada5e9d1aa732b435206..716b3fd1d86397ea57389a106516eb12073dde43 100644 (file)
@@ -2,7 +2,7 @@
 #define _ASM_SCORE_PGALLOC_H
 
 #include <linux/mm.h>
-
+#include <linux/highmem.h>
 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
        pte_t *pte)
 {
index 7234ed09b7b7ef5e815b749d8f364921a04b6500..befb87d30a89a0d9d21a774fb8d542963224a6ff 100644 (file)
@@ -264,7 +264,7 @@ resume_kernel:
        disable_irq
        lw      r8, [r28, TI_PRE_COUNT]
        cmpz.c  r8
-       bne     r8, restore_all
+       bne     restore_all
 need_resched:
        lw      r8, [r28, TI_FLAGS]
        andri.c r9, r8, _TIF_NEED_RESCHED
@@ -415,7 +415,7 @@ ENTRY(handle_sys)
        sw      r9, [r0, PT_EPC]
 
        cmpi.c  r27, __NR_syscalls      # check syscall number
-       bgeu    illegal_syscall
+       bcs     illegal_syscall
 
        slli    r8, r27, 2              # get syscall routine
        la      r11, sys_call_table
index f4c6d02421d3168cd8b17e87906490b214e7de96..a1519ad3d49d68e0e3202ecadb5b6e1b027a7df3 100644 (file)
@@ -78,8 +78,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        p->thread.reg0 = (unsigned long) childregs;
        if (unlikely(p->flags & PF_KTHREAD)) {
                memset(childregs, 0, sizeof(struct pt_regs));
-               p->thread->reg12 = usp;
-               p->thread->reg13 = arg;
+               p->thread.reg12 = usp;
+               p->thread.reg13 = arg;
                p->thread.reg3 = (unsigned long) ret_from_kernel_thread;
        } else {
                *childregs = *current_pt_regs();
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..78c4fdb91bc57a425e9fd5978260088ef5072d34 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
@@ -507,12 +506,17 @@ config SUN_OPENPROMFS
          Only choose N if you know in advance that you will not need to modify
          OpenPROM settings on the running system.
 
-# Makefile helper
+# Makefile helpers
 config SPARC64_PCI
        bool
        default y
        depends on SPARC64 && PCI
 
+config SPARC64_PCI_MSI
+       bool
+       default y
+       depends on SPARC64_PCI && PCI_MSI
+
 endmenu
 
 menu "Executable file formats"
index e204f902e6c9f3088ef11ea8dd571c80ba48b7f4..7c90c50c200d307465c5f814c2b4256f1a01b016 100644 (file)
@@ -254,7 +254,7 @@ static int sun_fd_request_irq(void)
                once = 1;
 
                error = request_irq(FLOPPY_IRQ, sparc_floppy_irq,
-                                   IRQF_DISABLED, "floppy", NULL);
+                                   0, "floppy", NULL);
 
                return ((error == 0) ? 0 : -1);
        }
index 5080d16a832ffec0c813b30cf546340e5047a7fd..ec2e2e2aba7d8f15419aa12bc6f790993f8c54d4 100644 (file)
@@ -9,7 +9,7 @@
 
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-               asm goto("1:\n\t"
+               asm_volatile_goto("1:\n\t"
                         "nop\n\t"
                         "nop\n\t"
                         ".pushsection __jump_table,  \"aw\"\n\t"
index d432fb20358e1785c3f6d6d2f0784580497a76ae..d15cc1794b0ec4890d3f6f717680b3673e76a0a9 100644 (file)
@@ -1,3 +1,4 @@
+
 #
 # Makefile for the linux kernel.
 #
@@ -99,7 +100,7 @@ obj-$(CONFIG_STACKTRACE)     += stacktrace.o
 obj-$(CONFIG_SPARC64_PCI)    += pci.o pci_common.o psycho_common.o
 obj-$(CONFIG_SPARC64_PCI)    += pci_psycho.o pci_sabre.o pci_schizo.o
 obj-$(CONFIG_SPARC64_PCI)    += pci_sun4v.o pci_sun4v_asm.o pci_fire.o
-obj-$(CONFIG_PCI_MSI)        += pci_msi.o
+obj-$(CONFIG_SPARC64_PCI_MSI) += pci_msi.o
 
 obj-$(CONFIG_COMPAT)         += sys32.o sys_sparc32.o signal32.o
 
index 62d6b153ffa2e82d895a4e81b51b2abe9490aee8..dff60abbea012f30a8b55221cc8d7a3a60a762ea 100644 (file)
@@ -849,9 +849,8 @@ void ldom_reboot(const char *boot_command)
        if (boot_command && strlen(boot_command)) {
                unsigned long len;
 
-               strcpy(full_boot_str, "boot ");
-               strlcpy(full_boot_str + strlen("boot "), boot_command,
-                       sizeof(full_boot_str + strlen("boot ")));
+               snprintf(full_boot_str, sizeof(full_boot_str), "boot %s",
+                        boot_command);
                len = strlen(full_boot_str);
 
                if (reboot_data_supported) {
index 54df554b82d98a684a3cbd7710ea10998e0d1722..e01d75d40329f010a1cc3c41020e100c6488e334 100644 (file)
@@ -1249,12 +1249,12 @@ int ldc_bind(struct ldc_channel *lp, const char *name)
        snprintf(lp->rx_irq_name, LDC_IRQ_NAME_MAX, "%s RX", name);
        snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name);
 
-       err = request_irq(lp->cfg.rx_irq, ldc_rx, IRQF_DISABLED,
+       err = request_irq(lp->cfg.rx_irq, ldc_rx, 0,
                          lp->rx_irq_name, lp);
        if (err)
                return err;
 
-       err = request_irq(lp->cfg.tx_irq, ldc_tx, IRQF_DISABLED,
+       err = request_irq(lp->cfg.tx_irq, ldc_tx, 0,
                          lp->tx_irq_name, lp);
        if (err) {
                free_irq(lp->cfg.rx_irq, lp);
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 d385eaadece7a68fe603eeb625b3caedb3c4c345..70979846076332bf7771d8517afdcc3415518b17 100644 (file)
@@ -166,7 +166,7 @@ static inline int atomic_cmpxchg(atomic_t *v, int o, int n)
  *
  * Atomically sets @v to @i and returns old @v
  */
-static inline u64 atomic64_xchg(atomic64_t *v, u64 n)
+static inline long long atomic64_xchg(atomic64_t *v, long long n)
 {
        return xchg64(&v->counter, n);
 }
@@ -180,7 +180,8 @@ static inline u64 atomic64_xchg(atomic64_t *v, u64 n)
  * Atomically checks if @v holds @o and replaces it with @n if so.
  * Returns the old value at @v.
  */
-static inline u64 atomic64_cmpxchg(atomic64_t *v, u64 o, u64 n)
+static inline long long atomic64_cmpxchg(atomic64_t *v, long long o,
+                                       long long n)
 {
        return cmpxchg64(&v->counter, o, n);
 }
index 0d0395b1b1529d454f772ebb61e240d7fb41f52a..1ad4a1f7d42b8aa47eadbbb4cdcf2e50dc630fd0 100644 (file)
@@ -80,7 +80,7 @@ static inline void atomic_set(atomic_t *v, int n)
 /* A 64bit atomic type */
 
 typedef struct {
-       u64 __aligned(8) counter;
+       long long counter;
 } atomic64_t;
 
 #define ATOMIC64_INIT(val) { (val) }
@@ -91,14 +91,14 @@ typedef struct {
  *
  * Atomically reads the value of @v.
  */
-static inline u64 atomic64_read(const atomic64_t *v)
+static inline long long atomic64_read(const atomic64_t *v)
 {
        /*
         * Requires an atomic op to read both 32-bit parts consistently.
         * Casting away const is safe since the atomic support routines
         * do not write to memory if the value has not been modified.
         */
-       return _atomic64_xchg_add((u64 *)&v->counter, 0);
+       return _atomic64_xchg_add((long long *)&v->counter, 0);
 }
 
 /**
@@ -108,7 +108,7 @@ static inline u64 atomic64_read(const atomic64_t *v)
  *
  * Atomically adds @i to @v.
  */
-static inline void atomic64_add(u64 i, atomic64_t *v)
+static inline void atomic64_add(long long i, atomic64_t *v)
 {
        _atomic64_xchg_add(&v->counter, i);
 }
@@ -120,7 +120,7 @@ static inline void atomic64_add(u64 i, atomic64_t *v)
  *
  * Atomically adds @i to @v and returns @i + @v
  */
-static inline u64 atomic64_add_return(u64 i, atomic64_t *v)
+static inline long long atomic64_add_return(long long i, atomic64_t *v)
 {
        smp_mb();  /* barrier for proper semantics */
        return _atomic64_xchg_add(&v->counter, i) + i;
@@ -135,7 +135,8 @@ static inline u64 atomic64_add_return(u64 i, atomic64_t *v)
  * Atomically adds @a to @v, so long as @v was not already @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-static inline u64 atomic64_add_unless(atomic64_t *v, u64 a, u64 u)
+static inline long long atomic64_add_unless(atomic64_t *v, long long a,
+                                       long long u)
 {
        smp_mb();  /* barrier for proper semantics */
        return _atomic64_xchg_add_unless(&v->counter, a, u) != u;
@@ -151,7 +152,7 @@ static inline u64 atomic64_add_unless(atomic64_t *v, u64 a, u64 u)
  * atomic64_set() can't be just a raw store, since it would be lost if it
  * fell between the load and store of one of the other atomic ops.
  */
-static inline void atomic64_set(atomic64_t *v, u64 n)
+static inline void atomic64_set(atomic64_t *v, long long n)
 {
        _atomic64_xchg(&v->counter, n);
 }
@@ -236,11 +237,13 @@ extern struct __get_user __atomic_xchg_add_unless(volatile int *p,
 extern struct __get_user __atomic_or(volatile int *p, int *lock, int n);
 extern struct __get_user __atomic_andn(volatile int *p, int *lock, int n);
 extern struct __get_user __atomic_xor(volatile int *p, int *lock, int n);
-extern u64 __atomic64_cmpxchg(volatile u64 *p, int *lock, u64 o, u64 n);
-extern u64 __atomic64_xchg(volatile u64 *p, int *lock, u64 n);
-extern u64 __atomic64_xchg_add(volatile u64 *p, int *lock, u64 n);
-extern u64 __atomic64_xchg_add_unless(volatile u64 *p,
-                                     int *lock, u64 o, u64 n);
+extern long long __atomic64_cmpxchg(volatile long long *p, int *lock,
+                                       long long o, long long n);
+extern long long __atomic64_xchg(volatile long long *p, int *lock, long long n);
+extern long long __atomic64_xchg_add(volatile long long *p, int *lock,
+                                       long long n);
+extern long long __atomic64_xchg_add_unless(volatile long long *p,
+                                       int *lock, long long o, long long n);
 
 /* Return failure from the atomic wrappers. */
 struct __get_user __atomic_bad_address(int __user *addr);
index 4001d5eab4bb7f1fb59e6e62c924bd71b4b10e2f..0ccda3c425be0d3b19a27c13b68ad6b6eaa37525 100644 (file)
@@ -35,10 +35,10 @@ int _atomic_xchg(int *ptr, int n);
 int _atomic_xchg_add(int *v, int i);
 int _atomic_xchg_add_unless(int *v, int a, int u);
 int _atomic_cmpxchg(int *ptr, int o, int n);
-u64 _atomic64_xchg(u64 *v, u64 n);
-u64 _atomic64_xchg_add(u64 *v, u64 i);
-u64 _atomic64_xchg_add_unless(u64 *v, u64 a, u64 u);
-u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n);
+long long _atomic64_xchg(long long *v, long long n);
+long long _atomic64_xchg_add(long long *v, long long i);
+long long _atomic64_xchg_add_unless(long long *v, long long a, long long u);
+long long _atomic64_cmpxchg(long long *v, long long o, long long n);
 
 #define xchg(ptr, n)                                                   \
        ({                                                              \
@@ -53,7 +53,8 @@ u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n);
                if (sizeof(*(ptr)) != 4)                                \
                        __cmpxchg_called_with_bad_pointer();            \
                smp_mb();                                               \
-               (typeof(*(ptr)))_atomic_cmpxchg((int *)ptr, (int)o, (int)n); \
+               (typeof(*(ptr)))_atomic_cmpxchg((int *)ptr, (int)o,     \
+                                               (int)n);                \
        })
 
 #define xchg64(ptr, n)                                                 \
@@ -61,7 +62,8 @@ u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n);
                if (sizeof(*(ptr)) != 8)                                \
                        __xchg_called_with_bad_pointer();               \
                smp_mb();                                               \
-               (typeof(*(ptr)))_atomic64_xchg((u64 *)(ptr), (u64)(n)); \
+               (typeof(*(ptr)))_atomic64_xchg((long long *)(ptr),      \
+                                               (long long)(n));        \
        })
 
 #define cmpxchg64(ptr, o, n)                                           \
@@ -69,7 +71,8 @@ u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n);
                if (sizeof(*(ptr)) != 8)                                \
                        __cmpxchg_called_with_bad_pointer();            \
                smp_mb();                                               \
-               (typeof(*(ptr)))_atomic64_cmpxchg((u64 *)ptr, (u64)o, (u64)n); \
+               (typeof(*(ptr)))_atomic64_cmpxchg((long long *)ptr,     \
+                                       (long long)o, (long long)n);    \
        })
 
 #else
@@ -81,10 +84,11 @@ u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n);
                switch (sizeof(*(ptr))) {                               \
                case 4:                                                 \
                        __x = (typeof(__x))(unsigned long)              \
-                               __insn_exch4((ptr), (u32)(unsigned long)(n)); \
+                               __insn_exch4((ptr),                     \
+                                       (u32)(unsigned long)(n));       \
                        break;                                          \
                case 8:                                                 \
-                       __x = (typeof(__x))                     \
+                       __x = (typeof(__x))                             \
                                __insn_exch((ptr), (unsigned long)(n)); \
                        break;                                          \
                default:                                                \
@@ -103,10 +107,12 @@ u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n);
                switch (sizeof(*(ptr))) {                               \
                case 4:                                                 \
                        __x = (typeof(__x))(unsigned long)              \
-                               __insn_cmpexch4((ptr), (u32)(unsigned long)(n)); \
+                               __insn_cmpexch4((ptr),                  \
+                                       (u32)(unsigned long)(n));       \
                        break;                                          \
                case 8:                                                 \
-                       __x = (typeof(__x))__insn_cmpexch((ptr), (u64)(n)); \
+                       __x = (typeof(__x))__insn_cmpexch((ptr),        \
+                                               (long long)(n));        \
                        break;                                          \
                default:                                                \
                        __cmpxchg_called_with_bad_pointer();            \
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 63294f5a8efbca7820c891232c7f79303213e653..4f7ae39fa2022c537770bd10e1cbb0e231249b53 100644 (file)
 #ifndef _ASM_TILE_PERCPU_H
 #define _ASM_TILE_PERCPU_H
 
-register unsigned long __my_cpu_offset __asm__("tp");
-#define __my_cpu_offset __my_cpu_offset
-#define set_my_cpu_offset(tp) (__my_cpu_offset = (tp))
+register unsigned long my_cpu_offset_reg asm("tp");
+
+#ifdef CONFIG_PREEMPT
+/*
+ * For full preemption, we can't just use the register variable
+ * directly, since we need barrier() to hazard against it, causing the
+ * compiler to reload anything computed from a previous "tp" value.
+ * But we also don't want to use volatile asm, since we'd like the
+ * compiler to be able to cache the value across multiple percpu reads.
+ * So we use a fake stack read as a hazard against barrier().
+ * The 'U' constraint is like 'm' but disallows postincrement.
+ */
+static inline unsigned long __my_cpu_offset(void)
+{
+       unsigned long tp;
+       register unsigned long *sp asm("sp");
+       asm("move %0, tp" : "=r" (tp) : "U" (*sp));
+       return tp;
+}
+#define __my_cpu_offset __my_cpu_offset()
+#else
+/*
+ * We don't need to hazard against barrier() since "tp" doesn't ever
+ * change with PREEMPT_NONE, and with PREEMPT_VOLUNTARY it only
+ * changes at function call points, at which we are already re-reading
+ * the value of "tp" due to "my_cpu_offset_reg" being a global variable.
+ */
+#define __my_cpu_offset my_cpu_offset_reg
+#endif
+
+#define set_my_cpu_offset(tp) (my_cpu_offset_reg = (tp))
 
 #include <asm-generic/percpu.h>
 
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 df27a1fd94a310a759612a5c6706b1011a94f787..531f4c365351119eeb249904cc01fd60307931b4 100644 (file)
@@ -66,7 +66,7 @@ static struct hardwall_type hardwall_types[] = {
                0,
                "udn",
                LIST_HEAD_INIT(hardwall_types[HARDWALL_UDN].list),
-               __SPIN_LOCK_INITIALIZER(hardwall_types[HARDWALL_UDN].lock),
+               __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_UDN].lock),
                NULL
        },
 #ifndef __tilepro__
@@ -77,7 +77,7 @@ static struct hardwall_type hardwall_types[] = {
                1,  /* disabled pending hypervisor support */
                "idn",
                LIST_HEAD_INIT(hardwall_types[HARDWALL_IDN].list),
-               __SPIN_LOCK_INITIALIZER(hardwall_types[HARDWALL_IDN].lock),
+               __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_IDN].lock),
                NULL
        },
        {  /* access to user-space IPI */
@@ -87,7 +87,7 @@ static struct hardwall_type hardwall_types[] = {
                0,
                "ipi",
                LIST_HEAD_INIT(hardwall_types[HARDWALL_IPI].list),
-               __SPIN_LOCK_INITIALIZER(hardwall_types[HARDWALL_IPI].lock),
+               __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_IPI].lock),
                NULL
        },
 #endif
index 088d5c141e681084ce030165f303d15f4b69876f..2cbe6d5dd6b04db3ea071fb12c3dbb1866dc818e 100644 (file)
@@ -815,6 +815,9 @@ STD_ENTRY(interrupt_return)
        }
        bzt     r28, 1f
        bnz     r29, 1f
+       /* Disable interrupts explicitly for preemption. */
+       IRQ_DISABLE(r20,r21)
+       TRACE_IRQS_OFF
        jal     preempt_schedule_irq
        FEEDBACK_REENTER(interrupt_return)
 1:
index ec755d3f373467ebe271dd1743cc6f56b6f9d7da..b8fc497f24370c0d7c17536664cb19c40923e5bf 100644 (file)
@@ -841,6 +841,9 @@ STD_ENTRY(interrupt_return)
        }
        beqzt   r28, 1f
        bnez    r29, 1f
+       /* Disable interrupts explicitly for preemption. */
+       IRQ_DISABLE(r20,r21)
+       TRACE_IRQS_OFF
        jal     preempt_schedule_irq
        FEEDBACK_REENTER(interrupt_return)
 1:
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 362284af3afd31ab39081447b6f1295a866c0ab9..c93977a62116dfecd12a74376e307c89c7875b91 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mmzone.h>
 #include <linux/dcache.h>
 #include <linux/fs.h>
+#include <linux/string.h>
 #include <asm/backtrace.h>
 #include <asm/page.h>
 #include <asm/ucontext.h>
@@ -332,21 +333,18 @@ static void describe_addr(struct KBacktraceIterator *kbt,
        }
 
        if (vma->vm_file) {
-               char *s;
                p = d_path(&vma->vm_file->f_path, buf, bufsize);
                if (IS_ERR(p))
                        p = "?";
-               s = strrchr(p, '/');
-               if (s)
-                       p = s+1;
+               name = kbasename(p);
        } else {
-               p = "anon";
+               name = "anon";
        }
 
        /* Generate a string description of the vma info. */
-       namelen = strlen(p);
+       namelen = strlen(name);
        remaining = (bufsize - 1) - namelen;
-       memmove(buf, p, namelen);
+       memmove(buf, name, namelen);
        snprintf(buf + namelen, remaining, "[%lx+%lx] ",
                 vma->vm_start, vma->vm_end - vma->vm_start);
 }
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 759efa337be88ebaf72cd1047151a2489a7745cb..c89b211fd9e7c093ed26e932432b329974003a04 100644 (file)
@@ -107,19 +107,19 @@ unsigned long _atomic_xor(volatile unsigned long *p, unsigned long mask)
 EXPORT_SYMBOL(_atomic_xor);
 
 
-u64 _atomic64_xchg(u64 *v, u64 n)
+long long _atomic64_xchg(long long *v, long long n)
 {
        return __atomic64_xchg(v, __atomic_setup(v), n);
 }
 EXPORT_SYMBOL(_atomic64_xchg);
 
-u64 _atomic64_xchg_add(u64 *v, u64 i)
+long long _atomic64_xchg_add(long long *v, long long i)
 {
        return __atomic64_xchg_add(v, __atomic_setup(v), i);
 }
 EXPORT_SYMBOL(_atomic64_xchg_add);
 
-u64 _atomic64_xchg_add_unless(u64 *v, u64 a, u64 u)
+long long _atomic64_xchg_add_unless(long long *v, long long a, long long u)
 {
        /*
         * Note: argument order is switched here since it is easier
@@ -130,7 +130,7 @@ u64 _atomic64_xchg_add_unless(u64 *v, u64 a, u64 u)
 }
 EXPORT_SYMBOL(_atomic64_xchg_add_unless);
 
-u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n)
+long long _atomic64_cmpxchg(long long *v, long long o, long long n)
 {
        return __atomic64_cmpxchg(v, __atomic_setup(v), o, n);
 }
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..f67e839f06c845e406d81c8b2be285ced8b57448 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"
@@ -860,7 +860,7 @@ source "kernel/Kconfig.preempt"
 
 config X86_UP_APIC
        bool "Local APIC support on uniprocessors"
-       depends on X86_32 && !SMP && !X86_32_NON_STANDARD
+       depends on X86_32 && !SMP && !X86_32_NON_STANDARD && !PCI_MSI
        ---help---
          A local APIC (Advanced Programmable Interrupt Controller) is an
          integrated interrupt controller in the CPU. If you have a single-CPU
@@ -885,11 +885,11 @@ config X86_UP_IOAPIC
 
 config X86_LOCAL_APIC
        def_bool y
-       depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC
+       depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
 
 config X86_IO_APIC
        def_bool y
-       depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC
+       depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC || PCI_MSI
 
 config X86_VISWS_APIC
        def_bool y
@@ -1033,6 +1033,7 @@ config X86_REBOOTFIXUPS
 
 config MICROCODE
        tristate "CPU microcode loading support"
+       depends on CPU_SUP_AMD || CPU_SUP_INTEL
        select FW_LOADER
        ---help---
 
index 6c63c358a7e689070881361b003f102c154e9c96..7d6ba9db1be99696784aeba62343eeebff9c32dd 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_CRYPTO_SHA1_SSSE3) += sha1-ssse3.o
 obj-$(CONFIG_CRYPTO_CRC32_PCLMUL) += crc32-pclmul.o
 obj-$(CONFIG_CRYPTO_SHA256_SSSE3) += sha256-ssse3.o
 obj-$(CONFIG_CRYPTO_SHA512_SSSE3) += sha512-ssse3.o
+obj-$(CONFIG_CRYPTO_CRCT10DIF_PCLMUL) += crct10dif-pclmul.o
 
 # These modules require assembler to support AVX.
 ifeq ($(avx_supported),yes)
@@ -81,3 +82,4 @@ crc32c-intel-$(CONFIG_64BIT) += crc32c-pcl-intel-asm_64.o
 crc32-pclmul-y := crc32-pclmul_asm.o crc32-pclmul_glue.o
 sha256-ssse3-y := sha256-ssse3-asm.o sha256-avx-asm.o sha256-avx2-asm.o sha256_ssse3_glue.o
 sha512-ssse3-y := sha512-ssse3-asm.o sha512-avx-asm.o sha512-avx2-asm.o sha512_ssse3_glue.o
+crct10dif-pclmul-y := crct10dif-pcl-asm_64.o crct10dif-pclmul_glue.o
index 5cb86ccd4acb9e6e105098525cb8fd7592a0cbd6..c171dcbf192d9b2ae1aa31c5b91f02ffb0b9220d 100644 (file)
@@ -62,7 +62,7 @@ static void camellia_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 }
 
 /* camellia sboxes */
-const u64 camellia_sp10011110[256] = {
+__visible const u64 camellia_sp10011110[256] = {
        0x7000007070707000ULL, 0x8200008282828200ULL, 0x2c00002c2c2c2c00ULL,
        0xec0000ecececec00ULL, 0xb30000b3b3b3b300ULL, 0x2700002727272700ULL,
        0xc00000c0c0c0c000ULL, 0xe50000e5e5e5e500ULL, 0xe40000e4e4e4e400ULL,
@@ -151,7 +151,7 @@ const u64 camellia_sp10011110[256] = {
        0x9e00009e9e9e9e00ULL,
 };
 
-const u64 camellia_sp22000222[256] = {
+__visible const u64 camellia_sp22000222[256] = {
        0xe0e0000000e0e0e0ULL, 0x0505000000050505ULL, 0x5858000000585858ULL,
        0xd9d9000000d9d9d9ULL, 0x6767000000676767ULL, 0x4e4e0000004e4e4eULL,
        0x8181000000818181ULL, 0xcbcb000000cbcbcbULL, 0xc9c9000000c9c9c9ULL,
@@ -240,7 +240,7 @@ const u64 camellia_sp22000222[256] = {
        0x3d3d0000003d3d3dULL,
 };
 
-const u64 camellia_sp03303033[256] = {
+__visible const u64 camellia_sp03303033[256] = {
        0x0038380038003838ULL, 0x0041410041004141ULL, 0x0016160016001616ULL,
        0x0076760076007676ULL, 0x00d9d900d900d9d9ULL, 0x0093930093009393ULL,
        0x0060600060006060ULL, 0x00f2f200f200f2f2ULL, 0x0072720072007272ULL,
@@ -329,7 +329,7 @@ const u64 camellia_sp03303033[256] = {
        0x004f4f004f004f4fULL,
 };
 
-const u64 camellia_sp00444404[256] = {
+__visible const u64 camellia_sp00444404[256] = {
        0x0000707070700070ULL, 0x00002c2c2c2c002cULL, 0x0000b3b3b3b300b3ULL,
        0x0000c0c0c0c000c0ULL, 0x0000e4e4e4e400e4ULL, 0x0000575757570057ULL,
        0x0000eaeaeaea00eaULL, 0x0000aeaeaeae00aeULL, 0x0000232323230023ULL,
@@ -418,7 +418,7 @@ const u64 camellia_sp00444404[256] = {
        0x00009e9e9e9e009eULL,
 };
 
-const u64 camellia_sp02220222[256] = {
+__visible const u64 camellia_sp02220222[256] = {
        0x00e0e0e000e0e0e0ULL, 0x0005050500050505ULL, 0x0058585800585858ULL,
        0x00d9d9d900d9d9d9ULL, 0x0067676700676767ULL, 0x004e4e4e004e4e4eULL,
        0x0081818100818181ULL, 0x00cbcbcb00cbcbcbULL, 0x00c9c9c900c9c9c9ULL,
@@ -507,7 +507,7 @@ const u64 camellia_sp02220222[256] = {
        0x003d3d3d003d3d3dULL,
 };
 
-const u64 camellia_sp30333033[256] = {
+__visible const u64 camellia_sp30333033[256] = {
        0x3800383838003838ULL, 0x4100414141004141ULL, 0x1600161616001616ULL,
        0x7600767676007676ULL, 0xd900d9d9d900d9d9ULL, 0x9300939393009393ULL,
        0x6000606060006060ULL, 0xf200f2f2f200f2f2ULL, 0x7200727272007272ULL,
@@ -596,7 +596,7 @@ const u64 camellia_sp30333033[256] = {
        0x4f004f4f4f004f4fULL,
 };
 
-const u64 camellia_sp44044404[256] = {
+__visible const u64 camellia_sp44044404[256] = {
        0x7070007070700070ULL, 0x2c2c002c2c2c002cULL, 0xb3b300b3b3b300b3ULL,
        0xc0c000c0c0c000c0ULL, 0xe4e400e4e4e400e4ULL, 0x5757005757570057ULL,
        0xeaea00eaeaea00eaULL, 0xaeae00aeaeae00aeULL, 0x2323002323230023ULL,
@@ -685,7 +685,7 @@ const u64 camellia_sp44044404[256] = {
        0x9e9e009e9e9e009eULL,
 };
 
-const u64 camellia_sp11101110[256] = {
+__visible const u64 camellia_sp11101110[256] = {
        0x7070700070707000ULL, 0x8282820082828200ULL, 0x2c2c2c002c2c2c00ULL,
        0xececec00ececec00ULL, 0xb3b3b300b3b3b300ULL, 0x2727270027272700ULL,
        0xc0c0c000c0c0c000ULL, 0xe5e5e500e5e5e500ULL, 0xe4e4e400e4e4e400ULL,
@@ -828,8 +828,8 @@ static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
 
        subRL[1] ^= (subRL[1] & ~subRL[9]) << 32;
        /* modified for FLinv(kl2) */
-       dw = (subRL[1] & subRL[9]) >> 32,
-               subRL[1] ^= rol32(dw, 1);
+       dw = (subRL[1] & subRL[9]) >> 32;
+       subRL[1] ^= rol32(dw, 1);
 
        /* round 8 */
        subRL[11] ^= subRL[1];
@@ -840,8 +840,8 @@ static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
 
        subRL[1] ^= (subRL[1] & ~subRL[17]) << 32;
        /* modified for FLinv(kl4) */
-       dw = (subRL[1] & subRL[17]) >> 32,
-               subRL[1] ^= rol32(dw, 1);
+       dw = (subRL[1] & subRL[17]) >> 32;
+       subRL[1] ^= rol32(dw, 1);
 
        /* round 14 */
        subRL[19] ^= subRL[1];
@@ -859,8 +859,8 @@ static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
        } else {
                subRL[1] ^= (subRL[1] & ~subRL[25]) << 32;
                /* modified for FLinv(kl6) */
-               dw = (subRL[1] & subRL[25]) >> 32,
-                       subRL[1] ^= rol32(dw, 1);
+               dw = (subRL[1] & subRL[25]) >> 32;
+               subRL[1] ^= rol32(dw, 1);
 
                /* round 20 */
                subRL[27] ^= subRL[1];
@@ -882,8 +882,8 @@ static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
 
                kw4 ^= (kw4 & ~subRL[24]) << 32;
                /* modified for FL(kl5) */
-               dw = (kw4 & subRL[24]) >> 32,
-                       kw4 ^= rol32(dw, 1);
+               dw = (kw4 & subRL[24]) >> 32;
+               kw4 ^= rol32(dw, 1);
        }
 
        /* round 17 */
@@ -895,8 +895,8 @@ static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
 
        kw4 ^= (kw4 & ~subRL[16]) << 32;
        /* modified for FL(kl3) */
-       dw = (kw4 & subRL[16]) >> 32,
-               kw4 ^= rol32(dw, 1);
+       dw = (kw4 & subRL[16]) >> 32;
+       kw4 ^= rol32(dw, 1);
 
        /* round 11 */
        subRL[14] ^= kw4;
@@ -907,8 +907,8 @@ static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
 
        kw4 ^= (kw4 & ~subRL[8]) << 32;
        /* modified for FL(kl1) */
-       dw = (kw4 & subRL[8]) >> 32,
-               kw4 ^= rol32(dw, 1);
+       dw = (kw4 & subRL[8]) >> 32;
+       kw4 ^= rol32(dw, 1);
 
        /* round 5 */
        subRL[6] ^= kw4;
@@ -928,8 +928,8 @@ static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
        SET_SUBKEY_LR(6, subRL[5] ^ subRL[7]);                  /* round 5 */
 
        tl = (subRL[10] >> 32) ^ (subRL[10] & ~subRL[8]);
-       dw = tl & (subRL[8] >> 32),                             /* FL(kl1) */
-               tr = subRL[10] ^ rol32(dw, 1);
+       dw = tl & (subRL[8] >> 32);                             /* FL(kl1) */
+       tr = subRL[10] ^ rol32(dw, 1);
        tt = (tr | ((u64)tl << 32));
 
        SET_SUBKEY_LR(7, subRL[6] ^ tt);                        /* round 6 */
@@ -937,8 +937,8 @@ static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
        SET_SUBKEY_LR(9, subRL[9]);                             /* FLinv(kl2) */
 
        tl = (subRL[7] >> 32) ^ (subRL[7] & ~subRL[9]);
-       dw = tl & (subRL[9] >> 32),                             /* FLinv(kl2) */
-               tr = subRL[7] ^ rol32(dw, 1);
+       dw = tl & (subRL[9] >> 32);                             /* FLinv(kl2) */
+       tr = subRL[7] ^ rol32(dw, 1);
        tt = (tr | ((u64)tl << 32));
 
        SET_SUBKEY_LR(10, subRL[11] ^ tt);                      /* round 7 */
@@ -948,8 +948,8 @@ static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
        SET_SUBKEY_LR(14, subRL[13] ^ subRL[15]);               /* round 11 */
 
        tl = (subRL[18] >> 32) ^ (subRL[18] & ~subRL[16]);
-       dw = tl & (subRL[16] >> 32),                            /* FL(kl3) */
-               tr = subRL[18] ^ rol32(dw, 1);
+       dw = tl & (subRL[16] >> 32);                            /* FL(kl3) */
+       tr = subRL[18] ^ rol32(dw, 1);
        tt = (tr | ((u64)tl << 32));
 
        SET_SUBKEY_LR(15, subRL[14] ^ tt);                      /* round 12 */
@@ -957,8 +957,8 @@ static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
        SET_SUBKEY_LR(17, subRL[17]);                           /* FLinv(kl4) */
 
        tl = (subRL[15] >> 32) ^ (subRL[15] & ~subRL[17]);
-       dw = tl & (subRL[17] >> 32),                            /* FLinv(kl4) */
-               tr = subRL[15] ^ rol32(dw, 1);
+       dw = tl & (subRL[17] >> 32);                            /* FLinv(kl4) */
+       tr = subRL[15] ^ rol32(dw, 1);
        tt = (tr | ((u64)tl << 32));
 
        SET_SUBKEY_LR(18, subRL[19] ^ tt);                      /* round 13 */
@@ -972,8 +972,8 @@ static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
                SET_SUBKEY_LR(24, subRL[24] ^ subRL[23]);       /* kw3 */
        } else {
                tl = (subRL[26] >> 32) ^ (subRL[26] & ~subRL[24]);
-               dw = tl & (subRL[24] >> 32),                    /* FL(kl5) */
-                       tr = subRL[26] ^ rol32(dw, 1);
+               dw = tl & (subRL[24] >> 32);                    /* FL(kl5) */
+               tr = subRL[26] ^ rol32(dw, 1);
                tt = (tr | ((u64)tl << 32));
 
                SET_SUBKEY_LR(23, subRL[22] ^ tt);              /* round 18 */
@@ -981,8 +981,8 @@ static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
                SET_SUBKEY_LR(25, subRL[25]);                   /* FLinv(kl6) */
 
                tl = (subRL[23] >> 32) ^ (subRL[23] & ~subRL[25]);
-               dw = tl & (subRL[25] >> 32),                    /* FLinv(kl6) */
-                       tr = subRL[23] ^ rol32(dw, 1);
+               dw = tl & (subRL[25] >> 32);                    /* FLinv(kl6) */
+               tr = subRL[23] ^ rol32(dw, 1);
                tt = (tr | ((u64)tl << 32));
 
                SET_SUBKEY_LR(26, subRL[27] ^ tt);              /* round 19 */
diff --git a/arch/x86/crypto/crct10dif-pcl-asm_64.S b/arch/x86/crypto/crct10dif-pcl-asm_64.S
new file mode 100644 (file)
index 0000000..35e9756
--- /dev/null
@@ -0,0 +1,643 @@
+########################################################################
+# Implement fast CRC-T10DIF computation with SSE and PCLMULQDQ instructions
+#
+# Copyright (c) 2013, Intel Corporation
+#
+# Authors:
+#     Erdinc Ozturk <erdinc.ozturk@intel.com>
+#     Vinodh Gopal <vinodh.gopal@intel.com>
+#     James Guilford <james.guilford@intel.com>
+#     Tim Chen <tim.c.chen@linux.intel.com>
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the
+#   distribution.
+#
+# * Neither the name of the Intel Corporation nor the names of its
+#   contributors may be used to endorse or promote products derived from
+#   this software without specific prior written permission.
+#
+#
+# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""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 INTEL CORPORATION 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.
+########################################################################
+#       Function API:
+#       UINT16 crc_t10dif_pcl(
+#               UINT16 init_crc, //initial CRC value, 16 bits
+#               const unsigned char *buf, //buffer pointer to calculate CRC on
+#               UINT64 len //buffer length in bytes (64-bit data)
+#       );
+#
+#       Reference paper titled "Fast CRC Computation for Generic
+#      Polynomials Using PCLMULQDQ Instruction"
+#       URL: http://www.intel.com/content/dam/www/public/us/en/documents
+#  /white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
+#
+#
+
+#include <linux/linkage.h>
+
+.text
+
+#define        arg1 %rdi
+#define        arg2 %rsi
+#define        arg3 %rdx
+
+#define        arg1_low32 %edi
+
+ENTRY(crc_t10dif_pcl)
+.align 16
+
+       # adjust the 16-bit initial_crc value, scale it to 32 bits
+       shl     $16, arg1_low32
+
+       # Allocate Stack Space
+       mov     %rsp, %rcx
+       sub     $16*2, %rsp
+       # align stack to 16 byte boundary
+       and     $~(0x10 - 1), %rsp
+
+       # check if smaller than 256
+       cmp     $256, arg3
+
+       # for sizes less than 128, we can't fold 64B at a time...
+       jl      _less_than_128
+
+
+       # load the initial crc value
+       movd    arg1_low32, %xmm10      # initial crc
+
+       # crc value does not need to be byte-reflected, but it needs
+       # to be moved to the high part of the register.
+       # because data will be byte-reflected and will align with
+       # initial crc at correct place.
+       pslldq  $12, %xmm10
+
+       movdqa  SHUF_MASK(%rip), %xmm11
+       # receive the initial 64B data, xor the initial crc value
+       movdqu  16*0(arg2), %xmm0
+       movdqu  16*1(arg2), %xmm1
+       movdqu  16*2(arg2), %xmm2
+       movdqu  16*3(arg2), %xmm3
+       movdqu  16*4(arg2), %xmm4
+       movdqu  16*5(arg2), %xmm5
+       movdqu  16*6(arg2), %xmm6
+       movdqu  16*7(arg2), %xmm7
+
+       pshufb  %xmm11, %xmm0
+       # XOR the initial_crc value
+       pxor    %xmm10, %xmm0
+       pshufb  %xmm11, %xmm1
+       pshufb  %xmm11, %xmm2
+       pshufb  %xmm11, %xmm3
+       pshufb  %xmm11, %xmm4
+       pshufb  %xmm11, %xmm5
+       pshufb  %xmm11, %xmm6
+       pshufb  %xmm11, %xmm7
+
+       movdqa  rk3(%rip), %xmm10       #xmm10 has rk3 and rk4
+                                       #imm value of pclmulqdq instruction
+                                       #will determine which constant to use
+
+       #################################################################
+       # we subtract 256 instead of 128 to save one instruction from the loop
+       sub     $256, arg3
+
+       # at this section of the code, there is 64*x+y (0<=y<64) bytes of
+       # buffer. The _fold_64_B_loop will fold 64B at a time
+       # until we have 64+y Bytes of buffer
+
+
+       # fold 64B at a time. This section of the code folds 4 xmm
+       # registers in parallel
+_fold_64_B_loop:
+
+       # update the buffer pointer
+       add     $128, arg2              #    buf += 64#
+
+       movdqu  16*0(arg2), %xmm9
+       movdqu  16*1(arg2), %xmm12
+       pshufb  %xmm11, %xmm9
+       pshufb  %xmm11, %xmm12
+       movdqa  %xmm0, %xmm8
+       movdqa  %xmm1, %xmm13
+       pclmulqdq       $0x0 , %xmm10, %xmm0
+       pclmulqdq       $0x11, %xmm10, %xmm8
+       pclmulqdq       $0x0 , %xmm10, %xmm1
+       pclmulqdq       $0x11, %xmm10, %xmm13
+       pxor    %xmm9 , %xmm0
+       xorps   %xmm8 , %xmm0
+       pxor    %xmm12, %xmm1
+       xorps   %xmm13, %xmm1
+
+       movdqu  16*2(arg2), %xmm9
+       movdqu  16*3(arg2), %xmm12
+       pshufb  %xmm11, %xmm9
+       pshufb  %xmm11, %xmm12
+       movdqa  %xmm2, %xmm8
+       movdqa  %xmm3, %xmm13
+       pclmulqdq       $0x0, %xmm10, %xmm2
+       pclmulqdq       $0x11, %xmm10, %xmm8
+       pclmulqdq       $0x0, %xmm10, %xmm3
+       pclmulqdq       $0x11, %xmm10, %xmm13
+       pxor    %xmm9 , %xmm2
+       xorps   %xmm8 , %xmm2
+       pxor    %xmm12, %xmm3
+       xorps   %xmm13, %xmm3
+
+       movdqu  16*4(arg2), %xmm9
+       movdqu  16*5(arg2), %xmm12
+       pshufb  %xmm11, %xmm9
+       pshufb  %xmm11, %xmm12
+       movdqa  %xmm4, %xmm8
+       movdqa  %xmm5, %xmm13
+       pclmulqdq       $0x0,  %xmm10, %xmm4
+       pclmulqdq       $0x11, %xmm10, %xmm8
+       pclmulqdq       $0x0,  %xmm10, %xmm5
+       pclmulqdq       $0x11, %xmm10, %xmm13
+       pxor    %xmm9 ,  %xmm4
+       xorps   %xmm8 ,  %xmm4
+       pxor    %xmm12,  %xmm5
+       xorps   %xmm13,  %xmm5
+
+       movdqu  16*6(arg2), %xmm9
+       movdqu  16*7(arg2), %xmm12
+       pshufb  %xmm11, %xmm9
+       pshufb  %xmm11, %xmm12
+       movdqa  %xmm6 , %xmm8
+       movdqa  %xmm7 , %xmm13
+       pclmulqdq       $0x0 , %xmm10, %xmm6
+       pclmulqdq       $0x11, %xmm10, %xmm8
+       pclmulqdq       $0x0 , %xmm10, %xmm7
+       pclmulqdq       $0x11, %xmm10, %xmm13
+       pxor    %xmm9 , %xmm6
+       xorps   %xmm8 , %xmm6
+       pxor    %xmm12, %xmm7
+       xorps   %xmm13, %xmm7
+
+       sub     $128, arg3
+
+       # check if there is another 64B in the buffer to be able to fold
+       jge     _fold_64_B_loop
+       ##################################################################
+
+
+       add     $128, arg2
+       # at this point, the buffer pointer is pointing at the last y Bytes
+       # of the buffer the 64B of folded data is in 4 of the xmm
+       # registers: xmm0, xmm1, xmm2, xmm3
+
+
+       # fold the 8 xmm registers to 1 xmm register with different constants
+
+       movdqa  rk9(%rip), %xmm10
+       movdqa  %xmm0, %xmm8
+       pclmulqdq       $0x11, %xmm10, %xmm0
+       pclmulqdq       $0x0 , %xmm10, %xmm8
+       pxor    %xmm8, %xmm7
+       xorps   %xmm0, %xmm7
+
+       movdqa  rk11(%rip), %xmm10
+       movdqa  %xmm1, %xmm8
+       pclmulqdq        $0x11, %xmm10, %xmm1
+       pclmulqdq        $0x0 , %xmm10, %xmm8
+       pxor    %xmm8, %xmm7
+       xorps   %xmm1, %xmm7
+
+       movdqa  rk13(%rip), %xmm10
+       movdqa  %xmm2, %xmm8
+       pclmulqdq        $0x11, %xmm10, %xmm2
+       pclmulqdq        $0x0 , %xmm10, %xmm8
+       pxor    %xmm8, %xmm7
+       pxor    %xmm2, %xmm7
+
+       movdqa  rk15(%rip), %xmm10
+       movdqa  %xmm3, %xmm8
+       pclmulqdq       $0x11, %xmm10, %xmm3
+       pclmulqdq       $0x0 , %xmm10, %xmm8
+       pxor    %xmm8, %xmm7
+       xorps   %xmm3, %xmm7
+
+       movdqa  rk17(%rip), %xmm10
+       movdqa  %xmm4, %xmm8
+       pclmulqdq       $0x11, %xmm10, %xmm4
+       pclmulqdq       $0x0 , %xmm10, %xmm8
+       pxor    %xmm8, %xmm7
+       pxor    %xmm4, %xmm7
+
+       movdqa  rk19(%rip), %xmm10
+       movdqa  %xmm5, %xmm8
+       pclmulqdq       $0x11, %xmm10, %xmm5
+       pclmulqdq       $0x0 , %xmm10, %xmm8
+       pxor    %xmm8, %xmm7
+       xorps   %xmm5, %xmm7
+
+       movdqa  rk1(%rip), %xmm10       #xmm10 has rk1 and rk2
+                                       #imm value of pclmulqdq instruction
+                                       #will determine which constant to use
+       movdqa  %xmm6, %xmm8
+       pclmulqdq       $0x11, %xmm10, %xmm6
+       pclmulqdq       $0x0 , %xmm10, %xmm8
+       pxor    %xmm8, %xmm7
+       pxor    %xmm6, %xmm7
+
+
+       # instead of 64, we add 48 to the loop counter to save 1 instruction
+       # from the loop instead of a cmp instruction, we use the negative
+       # flag with the jl instruction
+       add     $128-16, arg3
+       jl      _final_reduction_for_128
+
+       # now we have 16+y bytes left to reduce. 16 Bytes is in register xmm7
+       # and the rest is in memory. We can fold 16 bytes at a time if y>=16
+       # continue folding 16B at a time
+
+_16B_reduction_loop:
+       movdqa  %xmm7, %xmm8
+       pclmulqdq       $0x11, %xmm10, %xmm7
+       pclmulqdq       $0x0 , %xmm10, %xmm8
+       pxor    %xmm8, %xmm7
+       movdqu  (arg2), %xmm0
+       pshufb  %xmm11, %xmm0
+       pxor    %xmm0 , %xmm7
+       add     $16, arg2
+       sub     $16, arg3
+       # instead of a cmp instruction, we utilize the flags with the
+       # jge instruction equivalent of: cmp arg3, 16-16
+       # check if there is any more 16B in the buffer to be able to fold
+       jge     _16B_reduction_loop
+
+       #now we have 16+z bytes left to reduce, where 0<= z < 16.
+       #first, we reduce the data in the xmm7 register
+
+
+_final_reduction_for_128:
+       # check if any more data to fold. If not, compute the CRC of
+       # the final 128 bits
+       add     $16, arg3
+       je      _128_done
+
+       # here we are getting data that is less than 16 bytes.
+       # since we know that there was data before the pointer, we can
+       # offset the input pointer before the actual point, to receive
+       # exactly 16 bytes. after that the registers need to be adjusted.
+_get_last_two_xmms:
+       movdqa  %xmm7, %xmm2
+
+       movdqu  -16(arg2, arg3), %xmm1
+       pshufb  %xmm11, %xmm1
+
+       # get rid of the extra data that was loaded before
+       # load the shift constant
+       lea     pshufb_shf_table+16(%rip), %rax
+       sub     arg3, %rax
+       movdqu  (%rax), %xmm0
+
+       # shift xmm2 to the left by arg3 bytes
+       pshufb  %xmm0, %xmm2
+
+       # shift xmm7 to the right by 16-arg3 bytes
+       pxor    mask1(%rip), %xmm0
+       pshufb  %xmm0, %xmm7
+       pblendvb        %xmm2, %xmm1    #xmm0 is implicit
+
+       # fold 16 Bytes
+       movdqa  %xmm1, %xmm2
+       movdqa  %xmm7, %xmm8
+       pclmulqdq       $0x11, %xmm10, %xmm7
+       pclmulqdq       $0x0 , %xmm10, %xmm8
+       pxor    %xmm8, %xmm7
+       pxor    %xmm2, %xmm7
+
+_128_done:
+       # compute crc of a 128-bit value
+       movdqa  rk5(%rip), %xmm10       # rk5 and rk6 in xmm10
+       movdqa  %xmm7, %xmm0
+
+       #64b fold
+       pclmulqdq       $0x1, %xmm10, %xmm7
+       pslldq  $8   ,  %xmm0
+       pxor    %xmm0,  %xmm7
+
+       #32b fold
+       movdqa  %xmm7, %xmm0
+
+       pand    mask2(%rip), %xmm0
+
+       psrldq  $12, %xmm7
+       pclmulqdq       $0x10, %xmm10, %xmm7
+       pxor    %xmm0, %xmm7
+
+       #barrett reduction
+_barrett:
+       movdqa  rk7(%rip), %xmm10       # rk7 and rk8 in xmm10
+       movdqa  %xmm7, %xmm0
+       pclmulqdq       $0x01, %xmm10, %xmm7
+       pslldq  $4, %xmm7
+       pclmulqdq       $0x11, %xmm10, %xmm7
+
+       pslldq  $4, %xmm7
+       pxor    %xmm0, %xmm7
+       pextrd  $1, %xmm7, %eax
+
+_cleanup:
+       # scale the result back to 16 bits
+       shr     $16, %eax
+       mov     %rcx, %rsp
+       ret
+
+########################################################################
+
+.align 16
+_less_than_128:
+
+       # check if there is enough buffer to be able to fold 16B at a time
+       cmp     $32, arg3
+       jl      _less_than_32
+       movdqa  SHUF_MASK(%rip), %xmm11
+
+       # now if there is, load the constants
+       movdqa  rk1(%rip), %xmm10       # rk1 and rk2 in xmm10
+
+       movd    arg1_low32, %xmm0       # get the initial crc value
+       pslldq  $12, %xmm0      # align it to its correct place
+       movdqu  (arg2), %xmm7   # load the plaintext
+       pshufb  %xmm11, %xmm7   # byte-reflect the plaintext
+       pxor    %xmm0, %xmm7
+
+
+       # update the buffer pointer
+       add     $16, arg2
+
+       # update the counter. subtract 32 instead of 16 to save one
+       # instruction from the loop
+       sub     $32, arg3
+
+       jmp     _16B_reduction_loop
+
+
+.align 16
+_less_than_32:
+       # mov initial crc to the return value. this is necessary for
+       # zero-length buffers.
+       mov     arg1_low32, %eax
+       test    arg3, arg3
+       je      _cleanup
+
+       movdqa  SHUF_MASK(%rip), %xmm11
+
+       movd    arg1_low32, %xmm0       # get the initial crc value
+       pslldq  $12, %xmm0      # align it to its correct place
+
+       cmp     $16, arg3
+       je      _exact_16_left
+       jl      _less_than_16_left
+
+       movdqu  (arg2), %xmm7   # load the plaintext
+       pshufb  %xmm11, %xmm7   # byte-reflect the plaintext
+       pxor    %xmm0 , %xmm7   # xor the initial crc value
+       add     $16, arg2
+       sub     $16, arg3
+       movdqa  rk1(%rip), %xmm10       # rk1 and rk2 in xmm10
+       jmp     _get_last_two_xmms
+
+
+.align 16
+_less_than_16_left:
+       # use stack space to load data less than 16 bytes, zero-out
+       # the 16B in memory first.
+
+       pxor    %xmm1, %xmm1
+       mov     %rsp, %r11
+       movdqa  %xmm1, (%r11)
+
+       cmp     $4, arg3
+       jl      _only_less_than_4
+
+       # backup the counter value
+       mov     arg3, %r9
+       cmp     $8, arg3
+       jl      _less_than_8_left
+
+       # load 8 Bytes
+       mov     (arg2), %rax
+       mov     %rax, (%r11)
+       add     $8, %r11
+       sub     $8, arg3
+       add     $8, arg2
+_less_than_8_left:
+
+       cmp     $4, arg3
+       jl      _less_than_4_left
+
+       # load 4 Bytes
+       mov     (arg2), %eax
+       mov     %eax, (%r11)
+       add     $4, %r11
+       sub     $4, arg3
+       add     $4, arg2
+_less_than_4_left:
+
+       cmp     $2, arg3
+       jl      _less_than_2_left
+
+       # load 2 Bytes
+       mov     (arg2), %ax
+       mov     %ax, (%r11)
+       add     $2, %r11
+       sub     $2, arg3
+       add     $2, arg2
+_less_than_2_left:
+       cmp     $1, arg3
+        jl      _zero_left
+
+       # load 1 Byte
+       mov     (arg2), %al
+       mov     %al, (%r11)
+_zero_left:
+       movdqa  (%rsp), %xmm7
+       pshufb  %xmm11, %xmm7
+       pxor    %xmm0 , %xmm7   # xor the initial crc value
+
+       # shl r9, 4
+       lea     pshufb_shf_table+16(%rip), %rax
+       sub     %r9, %rax
+       movdqu  (%rax), %xmm0
+       pxor    mask1(%rip), %xmm0
+
+       pshufb  %xmm0, %xmm7
+       jmp     _128_done
+
+.align 16
+_exact_16_left:
+       movdqu  (arg2), %xmm7
+       pshufb  %xmm11, %xmm7
+       pxor    %xmm0 , %xmm7   # xor the initial crc value
+
+       jmp     _128_done
+
+_only_less_than_4:
+       cmp     $3, arg3
+       jl      _only_less_than_3
+
+       # load 3 Bytes
+       mov     (arg2), %al
+       mov     %al, (%r11)
+
+       mov     1(arg2), %al
+       mov     %al, 1(%r11)
+
+       mov     2(arg2), %al
+       mov     %al, 2(%r11)
+
+       movdqa   (%rsp), %xmm7
+       pshufb   %xmm11, %xmm7
+       pxor     %xmm0 , %xmm7  # xor the initial crc value
+
+       psrldq  $5, %xmm7
+
+       jmp     _barrett
+_only_less_than_3:
+       cmp     $2, arg3
+       jl      _only_less_than_2
+
+       # load 2 Bytes
+       mov     (arg2), %al
+       mov     %al, (%r11)
+
+       mov     1(arg2), %al
+       mov     %al, 1(%r11)
+
+       movdqa  (%rsp), %xmm7
+       pshufb  %xmm11, %xmm7
+       pxor    %xmm0 , %xmm7   # xor the initial crc value
+
+       psrldq  $6, %xmm7
+
+       jmp     _barrett
+_only_less_than_2:
+
+       # load 1 Byte
+       mov     (arg2), %al
+       mov     %al, (%r11)
+
+       movdqa  (%rsp), %xmm7
+       pshufb  %xmm11, %xmm7
+       pxor    %xmm0 , %xmm7   # xor the initial crc value
+
+       psrldq  $7, %xmm7
+
+       jmp     _barrett
+
+ENDPROC(crc_t10dif_pcl)
+
+.data
+
+# precomputed constants
+# these constants are precomputed from the poly:
+# 0x8bb70000 (0x8bb7 scaled to 32 bits)
+.align 16
+# Q = 0x18BB70000
+# rk1 = 2^(32*3) mod Q << 32
+# rk2 = 2^(32*5) mod Q << 32
+# rk3 = 2^(32*15) mod Q << 32
+# rk4 = 2^(32*17) mod Q << 32
+# rk5 = 2^(32*3) mod Q << 32
+# rk6 = 2^(32*2) mod Q << 32
+# rk7 = floor(2^64/Q)
+# rk8 = Q
+rk1:
+.quad 0x2d56000000000000
+rk2:
+.quad 0x06df000000000000
+rk3:
+.quad 0x9d9d000000000000
+rk4:
+.quad 0x7cf5000000000000
+rk5:
+.quad 0x2d56000000000000
+rk6:
+.quad 0x1368000000000000
+rk7:
+.quad 0x00000001f65a57f8
+rk8:
+.quad 0x000000018bb70000
+
+rk9:
+.quad 0xceae000000000000
+rk10:
+.quad 0xbfd6000000000000
+rk11:
+.quad 0x1e16000000000000
+rk12:
+.quad 0x713c000000000000
+rk13:
+.quad 0xf7f9000000000000
+rk14:
+.quad 0x80a6000000000000
+rk15:
+.quad 0x044c000000000000
+rk16:
+.quad 0xe658000000000000
+rk17:
+.quad 0xad18000000000000
+rk18:
+.quad 0xa497000000000000
+rk19:
+.quad 0x6ee3000000000000
+rk20:
+.quad 0xe7b5000000000000
+
+
+
+mask1:
+.octa 0x80808080808080808080808080808080
+mask2:
+.octa 0x00000000FFFFFFFFFFFFFFFFFFFFFFFF
+
+SHUF_MASK:
+.octa 0x000102030405060708090A0B0C0D0E0F
+
+pshufb_shf_table:
+# use these values for shift constants for the pshufb instruction
+# different alignments result in values as shown:
+#      DDQ 0x008f8e8d8c8b8a898887868584838281 # shl 15 (16-1) / shr1
+#      DDQ 0x01008f8e8d8c8b8a8988878685848382 # shl 14 (16-3) / shr2
+#      DDQ 0x0201008f8e8d8c8b8a89888786858483 # shl 13 (16-4) / shr3
+#      DDQ 0x030201008f8e8d8c8b8a898887868584 # shl 12 (16-4) / shr4
+#      DDQ 0x04030201008f8e8d8c8b8a8988878685 # shl 11 (16-5) / shr5
+#      DDQ 0x0504030201008f8e8d8c8b8a89888786 # shl 10 (16-6) / shr6
+#      DDQ 0x060504030201008f8e8d8c8b8a898887 # shl 9  (16-7) / shr7
+#      DDQ 0x07060504030201008f8e8d8c8b8a8988 # shl 8  (16-8) / shr8
+#      DDQ 0x0807060504030201008f8e8d8c8b8a89 # shl 7  (16-9) / shr9
+#      DDQ 0x090807060504030201008f8e8d8c8b8a # shl 6  (16-10) / shr10
+#      DDQ 0x0a090807060504030201008f8e8d8c8b # shl 5  (16-11) / shr11
+#      DDQ 0x0b0a090807060504030201008f8e8d8c # shl 4  (16-12) / shr12
+#      DDQ 0x0c0b0a090807060504030201008f8e8d # shl 3  (16-13) / shr13
+#      DDQ 0x0d0c0b0a090807060504030201008f8e # shl 2  (16-14) / shr14
+#      DDQ 0x0e0d0c0b0a090807060504030201008f # shl 1  (16-15) / shr15
+.octa 0x8f8e8d8c8b8a89888786858483828100
+.octa 0x000e0d0c0b0a09080706050403020100
diff --git a/arch/x86/crypto/crct10dif-pclmul_glue.c b/arch/x86/crypto/crct10dif-pclmul_glue.c
new file mode 100644 (file)
index 0000000..7845d7f
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Cryptographic API.
+ *
+ * T10 Data Integrity Field CRC16 Crypto Transform using PCLMULQDQ Instructions
+ *
+ * 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>
+#include <asm/i387.h>
+#include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
+
+asmlinkage __u16 crc_t10dif_pcl(__u16 crc, const unsigned char *buf,
+                               size_t len);
+
+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);
+
+       if (irq_fpu_usable()) {
+               kernel_fpu_begin();
+               ctx->crc = crc_t10dif_pcl(ctx->crc, data, length);
+               kernel_fpu_end();
+       } else
+               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)
+{
+       if (irq_fpu_usable()) {
+               kernel_fpu_begin();
+               *(__u16 *)out = crc_t10dif_pcl(*crcp, data, len);
+               kernel_fpu_end();
+       } else
+               *(__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-pclmul",
+               .cra_priority           =       200,
+               .cra_blocksize          =       CRC_T10DIF_BLOCK_SIZE,
+               .cra_module             =       THIS_MODULE,
+       }
+};
+
+static const struct x86_cpu_id crct10dif_cpu_id[] = {
+       X86_FEATURE_MATCH(X86_FEATURE_PCLMULQDQ),
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, crct10dif_cpu_id);
+
+static int __init crct10dif_intel_mod_init(void)
+{
+       if (!x86_match_cpu(crct10dif_cpu_id))
+               return -ENODEV;
+
+       return crypto_register_shash(&alg);
+}
+
+static void __exit crct10dif_intel_mod_fini(void)
+{
+       crypto_unregister_shash(&alg);
+}
+
+module_init(crct10dif_intel_mod_init);
+module_exit(crct10dif_intel_mod_fini);
+
+MODULE_AUTHOR("Tim Chen <tim.c.chen@linux.intel.com>");
+MODULE_DESCRIPTION("T10 DIF CRC calculation accelerated with PCLMULQDQ.");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("crct10dif");
+MODULE_ALIAS("crct10dif-pclmul");
index d3f5c63078d812e2f6220cfa5ad322aae920827c..89270b4318db8b97ac467717b38863fa549435ad 100644 (file)
@@ -374,7 +374,7 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
                 * Catch too early usage of this before alternatives
                 * have run.
                 */
-               asm goto("1: jmp %l[t_warn]\n"
+               asm_volatile_goto("1: jmp %l[t_warn]\n"
                         "2:\n"
                         ".section .altinstructions,\"a\"\n"
                         " .long 1b - .\n"
@@ -388,7 +388,7 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
 
 #endif
 
-               asm goto("1: jmp %l[t_no]\n"
+               asm_volatile_goto("1: jmp %l[t_no]\n"
                         "2:\n"
                         ".section .altinstructions,\"a\"\n"
                         " .long 1b - .\n"
@@ -453,7 +453,7 @@ static __always_inline __pure bool _static_cpu_has_safe(u16 bit)
  * have. Thus, we force the jump to the widest, 4-byte, signed relative
  * offset even though the last would often fit in less bytes.
  */
-               asm goto("1: .byte 0xe9\n .long %l[t_dynamic] - 2f\n"
+               asm_volatile_goto("1: .byte 0xe9\n .long %l[t_dynamic] - 2f\n"
                         "2:\n"
                         ".section .altinstructions,\"a\"\n"
                         " .long 1b - .\n"              /* src offset */
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..6a2cefb4395a4228cce550ef8b231f3e7158d9d1 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
+       asm_volatile_goto("1:"
+               ".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 e7e6751648edf775ad54a42a5c05b3e6d3c1cff5..07537a44216ec9b2eed302183af7c57d8949a5a0 100644 (file)
@@ -20,7 +20,7 @@
 static inline void __mutex_fastpath_lock(atomic_t *v,
                                         void (*fail_fn)(atomic_t *))
 {
-       asm volatile goto(LOCK_PREFIX "   decl %0\n"
+       asm_volatile_goto(LOCK_PREFIX "   decl %0\n"
                          "   jns %l[exit]\n"
                          : : "m" (v->counter)
                          : "memory", "cc"
@@ -75,7 +75,7 @@ static inline int __mutex_fastpath_lock_retval(atomic_t *count)
 static inline void __mutex_fastpath_unlock(atomic_t *v,
                                           void (*fail_fn)(atomic_t *))
 {
-       asm volatile goto(LOCK_PREFIX "   incl %0\n"
+       asm_volatile_goto(LOCK_PREFIX "   incl %0\n"
                          "   jg %l[exit]\n"
                          : : "m" (v->counter)
                          : "memory", "cc"
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 6aef9fbc09b7a48ec82c13e04b1f8c761dc34661..b913915e8e631f9c9ec2996fde3862bd33e2edce 100644 (file)
@@ -79,30 +79,38 @@ static inline int phys_to_machine_mapping_valid(unsigned long pfn)
        return get_phys_to_machine(pfn) != INVALID_P2M_ENTRY;
 }
 
-static inline unsigned long mfn_to_pfn(unsigned long mfn)
+static inline unsigned long mfn_to_pfn_no_overrides(unsigned long mfn)
 {
        unsigned long pfn;
-       int ret = 0;
+       int ret;
 
        if (xen_feature(XENFEAT_auto_translated_physmap))
                return mfn;
 
-       if (unlikely(mfn >= machine_to_phys_nr)) {
-               pfn = ~0;
-               goto try_override;
-       }
-       pfn = 0;
+       if (unlikely(mfn >= machine_to_phys_nr))
+               return ~0;
+
        /*
         * The array access can fail (e.g., device space beyond end of RAM).
         * In such cases it doesn't matter what we return (we return garbage),
         * but we must handle the fault without crashing!
         */
        ret = __get_user(pfn, &machine_to_phys_mapping[mfn]);
-try_override:
-       /* ret might be < 0 if there are no entries in the m2p for mfn */
        if (ret < 0)
-               pfn = ~0;
-       else if (get_phys_to_machine(pfn) != mfn)
+               return ~0;
+
+       return pfn;
+}
+
+static inline unsigned long mfn_to_pfn(unsigned long mfn)
+{
+       unsigned long pfn;
+
+       if (xen_feature(XENFEAT_auto_translated_physmap))
+               return mfn;
+
+       pfn = mfn_to_pfn_no_overrides(mfn);
+       if (get_phys_to_machine(pfn) != mfn) {
                /*
                 * If this appears to be a foreign mfn (because the pfn
                 * doesn't map back to the mfn), then check the local override
@@ -111,6 +119,7 @@ try_override:
                 * m2p_find_override_pfn returns ~0 if it doesn't find anything.
                 */
                pfn = m2p_find_override_pfn(mfn, ~0);
+       }
 
        /* 
         * pfn is ~0 if there are no entries in the m2p for mfn or if the
index 7ea79c5fa1f217ff3c8aaf0afba935411fe61c6e..492b29802f571b0363a22fe686f708c8235c317a 100644 (file)
@@ -167,12 +167,12 @@ static struct xor_block_template xor_block_avx = {
 
 #define AVX_XOR_SPEED \
 do { \
-       if (cpu_has_avx) \
+       if (cpu_has_avx && cpu_has_osxsave) \
                xor_speed(&xor_block_avx); \
 } while (0)
 
 #define AVX_SELECT(FASTEST) \
-       (cpu_has_avx ? &xor_block_avx : FASTEST)
+       (cpu_has_avx && cpu_has_osxsave ? &xor_block_avx : FASTEST)
 
 #else
 
index 1191ac1c9d2598e64d13a1419b4a7a383933ce03..a419814cea575f9e2cf183772a9e99c59e097a11 100644 (file)
@@ -113,7 +113,7 @@ static int __init early_get_pnodeid(void)
                break;
        case UV3_HUB_PART_NUMBER:
        case UV3_HUB_PART_NUMBER_X:
-               uv_min_hub_revision_id += UV3_HUB_REVISION_BASE - 1;
+               uv_min_hub_revision_id += UV3_HUB_REVISION_BASE;
                break;
        }
 
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 8355c84b9729df767945c5f4c8a5f7c5db15fab8..9d8449158cf989af3009c6606b7a878c827f5d32 100644 (file)
@@ -1506,7 +1506,7 @@ static int __init init_hw_perf_events(void)
                err = amd_pmu_init();
                break;
        default:
-               return 0;
+               err = -ENOTSUPP;
        }
        if (err != 0) {
                pr_cont("no PMU driver, software events only.\n");
@@ -1883,26 +1883,21 @@ static struct pmu pmu = {
 
 void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
 {
-       userpg->cap_usr_time = 0;
-       userpg->cap_usr_time_zero = 0;
-       userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc;
+       userpg->cap_user_time = 0;
+       userpg->cap_user_time_zero = 0;
+       userpg->cap_user_rdpmc = x86_pmu.attr_rdpmc;
        userpg->pmc_width = x86_pmu.cntval_bits;
 
-       if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
-               return;
-
-       if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+       if (!sched_clock_stable)
                return;
 
-       userpg->cap_usr_time = 1;
+       userpg->cap_user_time = 1;
        userpg->time_mult = this_cpu_read(cyc2ns);
        userpg->time_shift = CYC2NS_SCALE_FACTOR;
        userpg->time_offset = this_cpu_read(cyc2ns_offset) - now;
 
-       if (sched_clock_stable && !check_tsc_disabled()) {
-               userpg->cap_usr_time_zero = 1;
-               userpg->time_zero = this_cpu_read(cyc2ns_offset);
-       }
+       userpg->cap_user_time_zero = 1;
+       userpg->time_zero = this_cpu_read(cyc2ns_offset);
 }
 
 /*
index 0abf6742a8b0476a94d740f9cfb95b2fb090caba..f31a1655d1ff5bd602239e211b14bdd28d95a79a 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
 };
 
@@ -2324,6 +2325,7 @@ __init int intel_pmu_init(void)
                break;
 
        case 55: /* Atom 22nm "Silvermont" */
+       case 77: /* Avoton "Silvermont" */
                memcpy(hw_cache_event_ids, slm_hw_cache_event_ids,
                        sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, slm_hw_cache_extra_regs,
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..4118f9f683151e99402740f1882b205a261a1465 100644 (file)
@@ -2706,14 +2706,14 @@ static void uncore_pmu_init_hrtimer(struct intel_uncore_box *box)
        box->hrtimer.function = uncore_pmu_hrtimer;
 }
 
-struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type, int cpu)
+static struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type, int node)
 {
        struct intel_uncore_box *box;
        int i, size;
 
        size = sizeof(*box) + type->num_shared_regs * sizeof(struct intel_uncore_extra_reg);
 
-       box = kzalloc_node(size, GFP_KERNEL, cpu_to_node(cpu));
+       box = kzalloc_node(size, GFP_KERNEL, node);
        if (!box)
                return NULL;
 
@@ -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) {
@@ -3031,7 +3031,7 @@ static int uncore_validate_group(struct intel_uncore_pmu *pmu,
        struct intel_uncore_box *fake_box;
        int ret = -EINVAL, n;
 
-       fake_box = uncore_alloc_box(pmu->type, smp_processor_id());
+       fake_box = uncore_alloc_box(pmu->type, NUMA_NO_NODE);
        if (!fake_box)
                return -ENOMEM;
 
@@ -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) {
@@ -3292,7 +3294,7 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
        }
 
        type = pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)];
-       box = uncore_alloc_box(type, 0);
+       box = uncore_alloc_box(type, NUMA_NO_NODE);
        if (!box)
                return -ENOMEM;
 
@@ -3497,7 +3499,7 @@ static int uncore_cpu_prepare(int cpu, int phys_id)
                        if (pmu->func_id < 0)
                                pmu->func_id = j;
 
-                       box = uncore_alloc_box(type, cpu);
+                       box = uncore_alloc_box(type, cpu_to_node(cpu));
                        if (!box)
                                return -ENOMEM;
 
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 697b93af02ddbc0fb4461b5d853810fa250cd0a1..a0e2a8a80c94129bb3d3d47bf975ef68f98f500e 100644 (file)
@@ -775,11 +775,22 @@ void __init kvm_spinlock_init(void)
        if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT))
                return;
 
-       printk(KERN_INFO "KVM setup paravirtual spinlock\n");
+       pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(kvm_lock_spinning);
+       pv_lock_ops.unlock_kick = kvm_unlock_kick;
+}
+
+static __init int kvm_spinlock_init_jump(void)
+{
+       if (!kvm_para_available())
+               return 0;
+       if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT))
+               return 0;
 
        static_key_slow_inc(&paravirt_ticketlocks_enabled);
+       printk(KERN_INFO "KVM setup paravirtual spinlock\n");
 
-       pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(kvm_lock_spinning);
-       pv_lock_ops.unlock_kick = kvm_unlock_kick;
+       return 0;
 }
+early_initcall(kvm_spinlock_init_jump);
+
 #endif /* CONFIG_PARAVIRT_SPINLOCKS */
index 7123b5df479d872def8ff437fcd407c5c4d5ca50..af99f71aeb7f159a6ba7f1da0596ae2843d67e47 100644 (file)
@@ -216,6 +216,7 @@ int apply_microcode_amd(int cpu)
        /* need to apply patch? */
        if (rev >= mc_amd->hdr.patch_id) {
                c->microcode = rev;
+               uci->cpu_sig.rev = rev;
                return 0;
        }
 
index 563ed91e6faa3a2adac62ddeb8caff7e5ad50f24..7e920bff99a34b260e1ea338c3fc7dee44ba0e67 100644 (file)
@@ -326,6 +326,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"),
                },
        },
+       {       /* Handle problems with rebooting on the Latitude E5410. */
+               .callback = set_pci_reboot,
+               .ident = "Dell Latitude E5410",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5410"),
+               },
+       },
        {       /* Handle problems with rebooting on the Latitude E5420. */
                .callback = set_pci_reboot,
                .ident = "Dell Latitude E5420",
@@ -352,12 +360,28 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
        },
        {       /* Handle problems with rebooting on the Precision M6600. */
                .callback = set_pci_reboot,
-               .ident = "Dell OptiPlex 990",
+               .ident = "Dell Precision M6600",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"),
                },
        },
+       {       /* Handle problems with rebooting on the Dell PowerEdge C6100. */
+               .callback = set_pci_reboot,
+               .ident = "Dell PowerEdge C6100",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "C6100"),
+               },
+       },
+       {       /* Some C6100 machines were shipped with vendor being 'Dell'. */
+               .callback = set_pci_reboot,
+               .ident = "Dell PowerEdge C6100",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "C6100"),
+               },
+       },
        { }
 };
 
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 22513e96b0125c54510722afab5f7abab8f73405..86179d4098938d50e13f25b6e75cfe8a198b7b80 100644 (file)
@@ -72,14 +72,14 @@ __init int create_simplefb(const struct screen_info *si,
         * the part that is occupied by the framebuffer */
        len = mode->height * mode->stride;
        len = PAGE_ALIGN(len);
-       if (len > si->lfb_size << 16) {
+       if (len > (u64)si->lfb_size << 16) {
                printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
                return -EINVAL;
        }
 
        /* setup IORESOURCE_MEM as framebuffer memory */
        memset(&res, 0, sizeof(res));
-       res.flags = IORESOURCE_MEM;
+       res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
        res.name = simplefb_resname;
        res.start = si->lfb_base;
        res.end = si->lfb_base + len - 1;
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..2b2fce1b200900b1af42865f946d5faa25fdc56a 100644 (file)
@@ -3255,25 +3255,29 @@ static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
 
 static void ept_load_pdptrs(struct kvm_vcpu *vcpu)
 {
+       struct kvm_mmu *mmu = vcpu->arch.walk_mmu;
+
        if (!test_bit(VCPU_EXREG_PDPTR,
                      (unsigned long *)&vcpu->arch.regs_dirty))
                return;
 
        if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
-               vmcs_write64(GUEST_PDPTR0, vcpu->arch.mmu.pdptrs[0]);
-               vmcs_write64(GUEST_PDPTR1, vcpu->arch.mmu.pdptrs[1]);
-               vmcs_write64(GUEST_PDPTR2, vcpu->arch.mmu.pdptrs[2]);
-               vmcs_write64(GUEST_PDPTR3, vcpu->arch.mmu.pdptrs[3]);
+               vmcs_write64(GUEST_PDPTR0, mmu->pdptrs[0]);
+               vmcs_write64(GUEST_PDPTR1, mmu->pdptrs[1]);
+               vmcs_write64(GUEST_PDPTR2, mmu->pdptrs[2]);
+               vmcs_write64(GUEST_PDPTR3, mmu->pdptrs[3]);
        }
 }
 
 static void ept_save_pdptrs(struct kvm_vcpu *vcpu)
 {
+       struct kvm_mmu *mmu = vcpu->arch.walk_mmu;
+
        if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
-               vcpu->arch.mmu.pdptrs[0] = vmcs_read64(GUEST_PDPTR0);
-               vcpu->arch.mmu.pdptrs[1] = vmcs_read64(GUEST_PDPTR1);
-               vcpu->arch.mmu.pdptrs[2] = vmcs_read64(GUEST_PDPTR2);
-               vcpu->arch.mmu.pdptrs[3] = vmcs_read64(GUEST_PDPTR3);
+               mmu->pdptrs[0] = vmcs_read64(GUEST_PDPTR0);
+               mmu->pdptrs[1] = vmcs_read64(GUEST_PDPTR1);
+               mmu->pdptrs[2] = vmcs_read64(GUEST_PDPTR2);
+               mmu->pdptrs[3] = vmcs_read64(GUEST_PDPTR3);
        }
 
        __set_bit(VCPU_EXREG_PDPTR,
@@ -5339,6 +5343,17 @@ 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 (!(to_vmx(vcpu)->idt_vectoring_info & VECTORING_INFO_VALID_MASK) &&
+                       cpu_has_virtual_nmis() &&
+                       (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);
 
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 5596c7bdd327b1af38138a3d32be36be3e21cb17..082e88129712b4eb9e2027852c890a02ff31a1c7 100644 (file)
@@ -700,7 +700,7 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
        if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed)
                return -ENODEV;
 
-       if (start > end || !addr)
+       if (start > end)
                return -EINVAL;
 
        mutex_lock(&pci_mmcfg_lock);
@@ -716,6 +716,11 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
                return -EEXIST;
        }
 
+       if (!addr) {
+               mutex_unlock(&pci_mmcfg_lock);
+               return -EINVAL;
+       }
+
        rc = -EBUSY;
        cfg = pci_mmconfig_alloc(seg, start, end, addr);
        if (cfg == NULL) {
index 90f6ed127096566ab06c0a9e6f25a355ccdfc048..c7e22ab29a5a2eb6ce3dd75f0fd3e0b26be2d61b 100644 (file)
@@ -912,10 +912,13 @@ void __init efi_enter_virtual_mode(void)
 
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                md = p;
-               if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
-                   md->type != EFI_BOOT_SERVICES_CODE &&
-                   md->type != EFI_BOOT_SERVICES_DATA)
-                       continue;
+               if (!(md->attribute & EFI_MEMORY_RUNTIME)) {
+#ifdef CONFIG_X86_64
+                       if (md->type != EFI_BOOT_SERVICES_CODE &&
+                           md->type != EFI_BOOT_SERVICES_DATA)
+#endif
+                               continue;
+               }
 
                size = md->num_pages << EFI_PAGE_SHIFT;
                end = md->phys_addr + size;
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..a61c7d5811beac47e2549cd6fd44118bc5bf7b28 100644 (file)
@@ -879,7 +879,6 @@ int m2p_add_override(unsigned long mfn, struct page *page,
        unsigned long uninitialized_var(address);
        unsigned level;
        pte_t *ptep = NULL;
-       int ret = 0;
 
        pfn = page_to_pfn(page);
        if (!PageHighMem(page)) {
@@ -926,8 +925,8 @@ int m2p_add_override(unsigned long mfn, struct page *page,
         * frontend pages while they are being shared with the backend,
         * because mfn_to_pfn (that ends up being called by GUPF) will
         * return the backend pfn rather than the frontend pfn. */
-       ret = __get_user(pfn, &machine_to_phys_mapping[mfn]);
-       if (ret == 0 && get_phys_to_machine(pfn) == mfn)
+       pfn = mfn_to_pfn_no_overrides(mfn);
+       if (get_phys_to_machine(pfn) == mfn)
                set_phys_to_machine(pfn, FOREIGN_FRAME(mfn));
 
        return 0;
@@ -942,7 +941,6 @@ int m2p_remove_override(struct page *page,
        unsigned long uninitialized_var(address);
        unsigned level;
        pte_t *ptep = NULL;
-       int ret = 0;
 
        pfn = page_to_pfn(page);
        mfn = get_phys_to_machine(pfn);
@@ -990,10 +988,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 +1004,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;
@@ -1027,8 +1027,8 @@ int m2p_remove_override(struct page *page,
         * the original pfn causes mfn_to_pfn(mfn) to return the frontend
         * pfn again. */
        mfn &= ~FOREIGN_FRAME_BIT;
-       ret = __get_user(pfn, &machine_to_phys_mapping[mfn]);
-       if (ret == 0 && get_phys_to_machine(pfn) == FOREIGN_FRAME(mfn) &&
+       pfn = mfn_to_pfn_no_overrides(mfn);
+       if (get_phys_to_machine(pfn) == FOREIGN_FRAME(mfn) &&
                        m2p_find_override(mfn) == NULL)
                set_phys_to_machine(pfn, mfn);
 
index 9235842cd76a14bf39ae61f9e1026754beee9f8a..31d04758b76f6a2da41c309e368768d4881066d0 100644 (file)
@@ -273,12 +273,29 @@ 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();
+#ifdef CONFIG_X86_32
+               /*
+                * Xen starts us with XEN_FLAT_RING1_DS, but linux code
+                * expects __USER_DS
+                */
+               loadsegment(ds, __USER_DS);
+               loadsegment(es, __USER_DS);
+#endif
+
+               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 +726,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 +754,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..be6b8607895748304c860c61603d24a29bacfa34 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,28 +258,43 @@ void xen_uninit_lock_cpu(int cpu)
        per_cpu(irq_name, cpu) = NULL;
 }
 
-static bool xen_pvspin __initdata = true;
 
+/*
+ * Our init of PV spinlocks is split in two init functions due to us
+ * using paravirt patching and jump labels patching and having to do
+ * all of this before SMP code is invoked.
+ *
+ * The paravirt patching needs to be done _before_ the alternative asm code
+ * is started, otherwise we would not patch the core kernel code.
+ */
 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");
                return;
        }
 
-       static_key_slow_inc(&paravirt_ticketlocks_enabled);
-
        pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(xen_lock_spinning);
        pv_lock_ops.unlock_kick = xen_unlock_kick;
 }
 
+/*
+ * While the jump_label init code needs to happend _after_ the jump labels are
+ * enabled and before SMP is started. Hence we use pre-SMP initcall level
+ * init. We cannot do it in xen_init_spinlocks as that is done before
+ * jump labels are activated.
+ */
+static __init int xen_init_spinlocks_jump(void)
+{
+       if (!xen_pvspin)
+               return 0;
+
+       static_key_slow_inc(&paravirt_ticketlocks_enabled);
+       return 0;
+}
+early_initcall(xen_init_spinlocks_jump);
+
 static __init int xen_parse_nopvspin(char *arg)
 {
        xen_pvspin = false;
@@ -323,6 +313,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..2429515c05c2ed1b6f457a60def817c33c178651 100644 (file)
@@ -99,6 +99,17 @@ config BLK_DEV_THROTTLING
 
        See Documentation/cgroups/blkio-controller.txt for more information.
 
+config BLK_CMDLINE_PARSER
+       bool "Block device command line partition parser"
+       default n
+       ---help---
+       Enabling this option allows you to specify the partition layout from
+       the kernel boot args.  This is typically of use for embedded devices
+       which don't otherwise have any standardized method for listing the
+       partitions on a block device.
+
+       See Documentation/block/cmdline-partition.txt for more information.
+
 menu "Partition Types"
 
 source "block/partitions/Kconfig"
index 39b76ba66ffd5e3a5bdca0fcda2f5fbf0f4b9b55..671a83d063a5ba290c93efc08457eba6217ea80d 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_BLK_CMDLINE_PARSER)       += cmdline-parser.o
index e90c7c164c83b8dc58f36393bb5748c0110e6184..4e491d9b529255476939b8608d91718c40140059 100644 (file)
@@ -235,8 +235,13 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
        blkg->online = true;
        spin_unlock(&blkcg->lock);
 
-       if (!ret)
+       if (!ret) {
+               if (blkcg == &blkcg_root) {
+                       q->root_blkg = blkg;
+                       q->root_rl.blkg = blkg;
+               }
                return blkg;
+       }
 
        /* @blkg failed fully initialized, use the usual release path */
        blkg_put(blkg);
@@ -334,6 +339,15 @@ static void blkg_destroy(struct blkcg_gq *blkg)
        if (rcu_dereference_raw(blkcg->blkg_hint) == blkg)
                rcu_assign_pointer(blkcg->blkg_hint, NULL);
 
+       /*
+        * If root blkg is destroyed.  Just clear the pointer since root_rl
+        * does not take reference on root blkg.
+        */
+       if (blkcg == &blkcg_root) {
+               blkg->q->root_blkg = NULL;
+               blkg->q->root_rl.blkg = NULL;
+       }
+
        /*
         * Put the reference taken at the time of creation so that when all
         * queues are gone, group can be destroyed.
@@ -360,13 +374,6 @@ static void blkg_destroy_all(struct request_queue *q)
                blkg_destroy(blkg);
                spin_unlock(&blkcg->lock);
        }
-
-       /*
-        * root blkg is destroyed.  Just clear the pointer since
-        * root_rl does not take reference on root blkg.
-        */
-       q->root_blkg = NULL;
-       q->root_rl.blkg = NULL;
 }
 
 /*
@@ -970,8 +977,6 @@ int blkcg_activate_policy(struct request_queue *q,
                ret = PTR_ERR(blkg);
                goto out_unlock;
        }
-       q->root_blkg = blkg;
-       q->root_rl.blkg = blkg;
 
        list_for_each_entry(blkg, &q->blkg_list, q_node)
                cnt++;
index c04505358342e132a0a3164cd154d12d52a7ad98..0a00e4ecf87cae37a3d310c8dfd32869ac24c161 100644 (file)
@@ -1549,11 +1549,9 @@ get_rq:
        if (plug) {
                /*
                 * If this is the first request added after a plug, fire
-                * of a plug trace. If others have been added before, check
-                * if we have multiple devices in this plug. If so, make a
-                * note to sort the list before dispatch.
+                * of a plug trace.
                 */
-               if (list_empty(&plug->list))
+               if (!request_count)
                        trace_block_plug(q);
                else {
                        if (request_count >= BLK_MAX_REQUEST_COUNT) {
index e7062139612914b95917405fc3da52e4498f066d..ae4f27d7944e9a662ddbb51464bd18e10f4707a4 100644 (file)
@@ -68,9 +68,9 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
        spin_lock_irq(q->queue_lock);
 
        if (unlikely(blk_queue_dying(q))) {
+               rq->cmd_flags |= REQ_QUIET; 
                rq->errors = -ENXIO;
-               if (rq->end_io)
-                       rq->end_io(rq, rq->errors);
+               __blk_end_request_all(rq, rq->errors);
                spin_unlock_irq(q->queue_lock);
                return;
        }
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;
 
index dabb9d02cf9a509655f67ae169ac0c3a706d8f8e..434944cbd761884f0f6d9ffdfe96adc00afd1e5c 100644 (file)
@@ -1803,7 +1803,7 @@ static u64 cfqg_prfill_avg_queue_size(struct seq_file *sf,
 
        if (samples) {
                v = blkg_stat_read(&cfqg->stats.avg_queue_size_sum);
-               do_div(v, samples);
+               v = div64_u64(v, samples);
        }
        __blkg_prfill_u64(sf, pd, v);
        return 0;
@@ -4358,7 +4358,7 @@ static int cfq_init_queue(struct request_queue *q, struct elevator_type *e)
        if (!eq)
                return -ENOMEM;
 
-       cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
+       cfqd = kzalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node);
        if (!cfqd) {
                kobject_put(&eq->kobj);
                return -ENOMEM;
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 20614a33236220d0e79d99a2cfaf99822327bc57..9ef66406c625412b79296d6e4f9186611b95b6f6 100644 (file)
@@ -346,7 +346,7 @@ static int deadline_init_queue(struct request_queue *q, struct elevator_type *e)
        if (!eq)
                return -ENOMEM;
 
-       dd = kmalloc_node(sizeof(*dd), GFP_KERNEL | __GFP_ZERO, q->node);
+       dd = kzalloc_node(sizeof(*dd), GFP_KERNEL, q->node);
        if (!dd) {
                kobject_put(&eq->kobj);
                return -ENOMEM;
index 668394d185885bc3fcc878697878a4cb07be899e..2bcbd8cc14d4b23780a3cfc262857a87f7c5d67e 100644 (file)
@@ -155,7 +155,7 @@ struct elevator_queue *elevator_alloc(struct request_queue *q,
 {
        struct elevator_queue *eq;
 
-       eq = kmalloc_node(sizeof(*eq), GFP_KERNEL | __GFP_ZERO, q->node);
+       eq = kzalloc_node(sizeof(*eq), GFP_KERNEL, q->node);
        if (unlikely(!eq))
                goto err;
 
index dadf42b454a383299231fa46abee1631aab53196..791f419431322882a915f88995df7b72552d5507 100644 (file)
@@ -1252,8 +1252,7 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
 {
        struct gendisk *disk;
 
-       disk = kmalloc_node(sizeof(struct gendisk),
-                               GFP_KERNEL | __GFP_ZERO, node_id);
+       disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id);
        if (disk) {
                if (!init_part_stats(&disk->part0)) {
                        kfree(disk);
index 4cebb2f0d2f406d6b11af7aad8e70c3d50bf3232..9b29a996c3114a3d09c41abdcaaa0f3f19abe3ff 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 BLK_CMDLINE_PARSER
+       help
+         Say Y here if you want to read the partition 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..5141b56
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 HUAWEI
+ * Author: Cai Zhiyong <caizhiyong@huawei.com>
+ *
+ * Read block device partition table from the command line.
+ * Typically used for fixed block (eMMC) embedded devices.
+ * It has no MBR, so saves 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.
+ *
+ * For further information, see "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..a8287b49d0621d1778295ad0516c8ccbf22ed0fa 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,89 @@ 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.
+        *
+        * Consider a bad value here to be a warning to support dd'ing
+        * an image from a smaller disk to a larger disk.
+        */
+       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)
+                       pr_debug("GPT: mbr size in lba (%u) different than whole disk (%u).\n",
+                                sz, min_t(uint32_t,
+                                          total_sectors - 1, 0xFFFFFFFF));
+       }
+done:
+       return ret;
 }
 
 /**
@@ -243,8 +301,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 +421,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 +491,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 +534,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 +542,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 +591,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 +599,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 +637,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 +646,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 +708,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 aca01164f00200a8d14efa8a82e4a400b67d0bf1..69ce573f1224560b4f5c7532e21053b27c651da4 100644 (file)
@@ -376,6 +376,25 @@ config CRYPTO_CRC32_PCLMUL
          which will enable any routine to use the CRC-32-IEEE 802.3 checksum
          and gain better performance as compared with the table implementation.
 
+config CRYPTO_CRCT10DIF
+       tristate "CRCT10DIF algorithm"
+       select CRYPTO_HASH
+       help
+         CRC T10 Data Integrity Field computation is being cast as
+         a crypto transform.  This allows for faster crc t10 diff
+         transforms to be used if they are available.
+
+config CRYPTO_CRCT10DIF_PCLMUL
+       tristate "CRCT10DIF PCLMULQDQ hardware acceleration"
+       depends on X86 && 64BIT && CRC_T10DIF
+       select CRYPTO_HASH
+       help
+         For x86_64 processors with SSE4.2 and PCLMULQDQ supported,
+         CRC T10 DIF PCLMULQDQ computation can be hardware
+         accelerated PCLMULQDQ instruction. This option will create
+         'crct10dif-plcmul' module, which is faster when computing the
+         crct10dif checksum as compared with the generic table implementation.
+
 config CRYPTO_GHASH
        tristate "GHASH digest algorithm"
        select CRYPTO_GF128MUL
index 2ba0df2f908f5985ef23f0794c1f49e6fd5f3720..80019ba8da3a2113ce8a48bf924bba9ca7d96e50 100644 (file)
@@ -83,6 +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_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 47f2e5c717591847ed598db32b209bd6f1bbd254..fd0d6b454975c4dba37c5d4cbaff179110351431 100644 (file)
@@ -62,7 +62,7 @@ static inline u8 byte(const u32 x, const unsigned n)
 
 static const u32 rco_tab[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 };
 
-const u32 crypto_ft_tab[4][256] = {
+__visible const u32 crypto_ft_tab[4][256] = {
        {
                0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6,
                0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591,
@@ -326,7 +326,7 @@ const u32 crypto_ft_tab[4][256] = {
        }
 };
 
-const u32 crypto_fl_tab[4][256] = {
+__visible const u32 crypto_fl_tab[4][256] = {
        {
                0x00000063, 0x0000007c, 0x00000077, 0x0000007b,
                0x000000f2, 0x0000006b, 0x0000006f, 0x000000c5,
@@ -590,7 +590,7 @@ const u32 crypto_fl_tab[4][256] = {
        }
 };
 
-const u32 crypto_it_tab[4][256] = {
+__visible const u32 crypto_it_tab[4][256] = {
        {
                0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a,
                0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b,
@@ -854,7 +854,7 @@ const u32 crypto_it_tab[4][256] = {
        }
 };
 
-const u32 crypto_il_tab[4][256] = {
+__visible const u32 crypto_il_tab[4][256] = {
        {
                0x00000052, 0x00000009, 0x0000006a, 0x000000d5,
                0x00000030, 0x00000036, 0x000000a5, 0x00000038,
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;
 }
index 75efa20523053661e35fe209feaab50b418dc364..26bcd7a2d6b473a2b2d1b12edd51b271705a46f0 100644 (file)
@@ -388,8 +388,8 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        /* round 6 */
        subL[7] ^= subL[1]; subR[7] ^= subR[1];
        subL[1] ^= subR[1] & ~subR[9];
-       dw = subL[1] & subL[9],
-               subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl2) */
+       dw = subL[1] & subL[9];
+       subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl2) */
        /* round 8 */
        subL[11] ^= subL[1]; subR[11] ^= subR[1];
        /* round 10 */
@@ -397,8 +397,8 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        /* round 12 */
        subL[15] ^= subL[1]; subR[15] ^= subR[1];
        subL[1] ^= subR[1] & ~subR[17];
-       dw = subL[1] & subL[17],
-               subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl4) */
+       dw = subL[1] & subL[17];
+       subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl4) */
        /* round 14 */
        subL[19] ^= subL[1]; subR[19] ^= subR[1];
        /* round 16 */
@@ -413,8 +413,8 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
                kw4l = subL[25]; kw4r = subR[25];
        } else {
                subL[1] ^= subR[1] & ~subR[25];
-               dw = subL[1] & subL[25],
-                       subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl6) */
+               dw = subL[1] & subL[25];
+               subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl6) */
                /* round 20 */
                subL[27] ^= subL[1]; subR[27] ^= subR[1];
                /* round 22 */
@@ -433,8 +433,8 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
                /* round 19 */
                subL[26] ^= kw4l; subR[26] ^= kw4r;
                kw4l ^= kw4r & ~subR[24];
-               dw = kw4l & subL[24],
-                       kw4r ^= rol32(dw, 1); /* modified for FL(kl5) */
+               dw = kw4l & subL[24];
+               kw4r ^= rol32(dw, 1); /* modified for FL(kl5) */
        }
        /* round 17 */
        subL[22] ^= kw4l; subR[22] ^= kw4r;
@@ -443,8 +443,8 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        /* round 13 */
        subL[18] ^= kw4l; subR[18] ^= kw4r;
        kw4l ^= kw4r & ~subR[16];
-       dw = kw4l & subL[16],
-               kw4r ^= rol32(dw, 1); /* modified for FL(kl3) */
+       dw = kw4l & subL[16];
+       kw4r ^= rol32(dw, 1); /* modified for FL(kl3) */
        /* round 11 */
        subL[14] ^= kw4l; subR[14] ^= kw4r;
        /* round 9 */
@@ -452,8 +452,8 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        /* round 7 */
        subL[10] ^= kw4l; subR[10] ^= kw4r;
        kw4l ^= kw4r & ~subR[8];
-       dw = kw4l & subL[8],
-               kw4r ^= rol32(dw, 1); /* modified for FL(kl1) */
+       dw = kw4l & subL[8];
+       kw4r ^= rol32(dw, 1); /* modified for FL(kl1) */
        /* round 5 */
        subL[6] ^= kw4l; subR[6] ^= kw4r;
        /* round 3 */
@@ -477,8 +477,8 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        SUBKEY_L(6) = subL[5] ^ subL[7]; /* round 5 */
        SUBKEY_R(6) = subR[5] ^ subR[7];
        tl = subL[10] ^ (subR[10] & ~subR[8]);
-       dw = tl & subL[8],  /* FL(kl1) */
-               tr = subR[10] ^ rol32(dw, 1);
+       dw = tl & subL[8];  /* FL(kl1) */
+       tr = subR[10] ^ rol32(dw, 1);
        SUBKEY_L(7) = subL[6] ^ tl; /* round 6 */
        SUBKEY_R(7) = subR[6] ^ tr;
        SUBKEY_L(8) = subL[8];       /* FL(kl1) */
@@ -486,8 +486,8 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        SUBKEY_L(9) = subL[9];       /* FLinv(kl2) */
        SUBKEY_R(9) = subR[9];
        tl = subL[7] ^ (subR[7] & ~subR[9]);
-       dw = tl & subL[9],  /* FLinv(kl2) */
-               tr = subR[7] ^ rol32(dw, 1);
+       dw = tl & subL[9];  /* FLinv(kl2) */
+       tr = subR[7] ^ rol32(dw, 1);
        SUBKEY_L(10) = tl ^ subL[11]; /* round 7 */
        SUBKEY_R(10) = tr ^ subR[11];
        SUBKEY_L(11) = subL[10] ^ subL[12]; /* round 8 */
@@ -499,8 +499,8 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        SUBKEY_L(14) = subL[13] ^ subL[15]; /* round 11 */
        SUBKEY_R(14) = subR[13] ^ subR[15];
        tl = subL[18] ^ (subR[18] & ~subR[16]);
-       dw = tl & subL[16], /* FL(kl3) */
-               tr = subR[18] ^ rol32(dw, 1);
+       dw = tl & subL[16]; /* FL(kl3) */
+       tr = subR[18] ^ rol32(dw, 1);
        SUBKEY_L(15) = subL[14] ^ tl; /* round 12 */
        SUBKEY_R(15) = subR[14] ^ tr;
        SUBKEY_L(16) = subL[16];     /* FL(kl3) */
@@ -508,8 +508,8 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        SUBKEY_L(17) = subL[17];     /* FLinv(kl4) */
        SUBKEY_R(17) = subR[17];
        tl = subL[15] ^ (subR[15] & ~subR[17]);
-       dw = tl & subL[17], /* FLinv(kl4) */
-               tr = subR[15] ^ rol32(dw, 1);
+       dw = tl & subL[17]; /* FLinv(kl4) */
+       tr = subR[15] ^ rol32(dw, 1);
        SUBKEY_L(18) = tl ^ subL[19]; /* round 13 */
        SUBKEY_R(18) = tr ^ subR[19];
        SUBKEY_L(19) = subL[18] ^ subL[20]; /* round 14 */
@@ -527,8 +527,8 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
                SUBKEY_R(24) = subR[24] ^ subR[23];
        } else {
                tl = subL[26] ^ (subR[26] & ~subR[24]);
-               dw = tl & subL[24], /* FL(kl5) */
-                       tr = subR[26] ^ rol32(dw, 1);
+               dw = tl & subL[24]; /* FL(kl5) */
+               tr = subR[26] ^ rol32(dw, 1);
                SUBKEY_L(23) = subL[22] ^ tl; /* round 18 */
                SUBKEY_R(23) = subR[22] ^ tr;
                SUBKEY_L(24) = subL[24];     /* FL(kl5) */
@@ -536,8 +536,8 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
                SUBKEY_L(25) = subL[25];     /* FLinv(kl6) */
                SUBKEY_R(25) = subR[25];
                tl = subL[23] ^ (subR[23] & ~subR[25]);
-               dw = tl & subL[25], /* FLinv(kl6) */
-                       tr = subR[23] ^ rol32(dw, 1);
+               dw = tl & subL[25]; /* FLinv(kl6) */
+               tr = subR[23] ^ rol32(dw, 1);
                SUBKEY_L(26) = tl ^ subL[27]; /* round 19 */
                SUBKEY_R(26) = tr ^ subR[27];
                SUBKEY_L(27) = subL[26] ^ subL[28]; /* round 20 */
index a15f523d5f56bc4195f4876164afd8e0d44ab58c..117dd8250f27b604d9cf1b4d6a95efa1e38dfedc 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/module.h>
 #include <crypto/cast_common.h>
 
-const u32 cast_s1[256] = {
+__visible const u32 cast_s1[256] = {
        0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f,
        0x9c004dd3, 0x6003e540, 0xcf9fc949,
        0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0,
@@ -83,7 +83,7 @@ const u32 cast_s1[256] = {
 };
 EXPORT_SYMBOL_GPL(cast_s1);
 
-const u32 cast_s2[256] = {
+__visible const u32 cast_s2[256] = {
        0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a,
        0xeec5207a, 0x55889c94, 0x72fc0651,
        0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef,
@@ -151,7 +151,7 @@ const u32 cast_s2[256] = {
 };
 EXPORT_SYMBOL_GPL(cast_s2);
 
-const u32 cast_s3[256] = {
+__visible const u32 cast_s3[256] = {
        0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff,
        0x369fe44b, 0x8c1fc644, 0xaececa90,
        0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806,
@@ -219,7 +219,7 @@ const u32 cast_s3[256] = {
 };
 EXPORT_SYMBOL_GPL(cast_s3);
 
-const u32 cast_s4[256] = {
+__visible const u32 cast_s4[256] = {
        0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb,
        0x64ad8c57, 0x85510443, 0xfa020ed1,
        0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43,
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 3b2cf569c684fa5c8a278a4919f9ee8513fb79b3..021d7fec6bc89e9b70af87b1e66a310268da28bb 100644 (file)
@@ -110,7 +110,7 @@ static const __be32 sbox0[256] = {
 };
 
 #undef Z
-#define Z(x) cpu_to_be32((x << 27) | (x >> 5))
+#define Z(x) cpu_to_be32(((x & 0x1f) << 27) | (x >> 5))
 static const __be32 sbox1[256] = {
        Z(0x77), Z(0x14), Z(0xa6), Z(0xfe), Z(0xb2), Z(0x5e), Z(0x8c), Z(0x3e),
        Z(0x67), Z(0x6c), Z(0xa1), Z(0x0d), Z(0xc2), Z(0xa2), Z(0xc1), Z(0x85),
index 7281b8a93ad3a4c486f3ca18721e73f79094659e..79ca2278c2a38a6c022d7d3ccbae30981434e238 100644 (file)
@@ -124,3 +124,25 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
        scatterwalk_done(&walk, out, 0);
 }
 EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy);
+
+int scatterwalk_bytes_sglen(struct scatterlist *sg, int num_bytes)
+{
+       int offset = 0, n = 0;
+
+       /* num_bytes is too small */
+       if (num_bytes < sg->length)
+               return -1;
+
+       do {
+               offset += sg->length;
+               n++;
+               sg = scatterwalk_sg_next(sg);
+
+               /* num_bytes is too large */
+               if (unlikely(!sg && (num_bytes < offset)))
+                       return -1;
+       } while (sg && (num_bytes > offset));
+
+       return n;
+}
+EXPORT_SYMBOL_GPL(scatterwalk_bytes_sglen);
index 66d254ce0d11b35ca55e07b8b0fd786c0b0f0c10..25a5934f0e50a011f73db08a84735ae76b2a7f60 100644 (file)
@@ -1174,6 +1174,10 @@ static int do_test(int m)
                ret += tcrypt_test("ghash");
                break;
 
+       case 47:
+               ret += tcrypt_test("crct10dif");
+               break;
+
        case 100:
                ret += tcrypt_test("hmac(md5)");
                break;
@@ -1498,6 +1502,10 @@ static int do_test(int m)
                test_hash_speed("crc32c", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
 
+       case 320:
+               test_hash_speed("crct10dif", sec, generic_hash_speed_template);
+               if (mode > 300 && mode < 400) break;
+
        case 399:
                break;
 
index ecddf921a9db401ee30bea1bf24b30f0ee8dd85d..e091ef6e17912b24020bf0a1668f33602b770cf9 100644 (file)
@@ -2045,6 +2045,16 @@ static const struct alg_test_desc alg_test_descs[] = {
                                .count = CRC32C_TEST_VECTORS
                        }
                }
+       }, {
+               .alg = "crct10dif",
+               .test = alg_test_hash,
+               .fips_allowed = 1,
+               .suite = {
+                       .hash = {
+                               .vecs = crct10dif_tv_template,
+                               .count = CRCT10DIF_TEST_VECTORS
+                       }
+               }
        }, {
                .alg = "cryptd(__driver-cbc-aes-aesni)",
                .test = alg_test_null,
@@ -3224,7 +3234,7 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
        if (i >= 0)
                rc |= alg_test_descs[i].test(alg_test_descs + i, driver,
                                             type, mask);
-       if (j >= 0)
+       if (j >= 0 && j != i)
                rc |= alg_test_descs[j].test(alg_test_descs + j, driver,
                                             type, mask);
 
index 1e701bc075b907521c0e0cd4a06e41858cda0a5f..7d44aa3d6b4472646dd9b93a77d97a0a58762eae 100644 (file)
@@ -450,6 +450,39 @@ static struct hash_testvec rmd320_tv_template[] = {
        }
 };
 
+#define CRCT10DIF_TEST_VECTORS 3
+static struct hash_testvec crct10dif_tv_template[] = {
+       {
+               .plaintext = "abc",
+               .psize  = 3,
+#ifdef __LITTLE_ENDIAN
+               .digest = "\x3b\x44",
+#else
+               .digest = "\x44\x3b",
+#endif
+       }, {
+               .plaintext = "1234567890123456789012345678901234567890"
+                            "123456789012345678901234567890123456789",
+               .psize  = 79,
+#ifdef __LITTLE_ENDIAN
+               .digest = "\x70\x4b",
+#else
+               .digest = "\x4b\x70",
+#endif
+       }, {
+               .plaintext =
+               "abcddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+               .psize  = 56,
+#ifdef __LITTLE_ENDIAN
+               .digest = "\xe3\x9c",
+#else
+               .digest = "\x9c\xe3",
+#endif
+               .np     = 2,
+               .tap    = { 28, 28 }
+       }
+};
+
 /*
  * SHA1 test vectors  from from FIPS PUB 180-1
  * Long vector from CAVS 5.0
index 22327e6a7236fc367313ec5acf45016d354863d4..6efe2ac6902fa635bf90a2d3e3d14728949aad5c 100644 (file)
@@ -24,7 +24,7 @@ menuconfig ACPI
          are configured, ACPI is used.
 
          The project home page for the Linux ACPI subsystem is here:
-         <http://www.lesswatts.org/projects/acpi/>
+         <https://01.org/linux-acpi>
 
          Linux support for ACPI is based on Intel Corporation's ACPI
          Component Architecture (ACPI CA).  For more information on the
@@ -123,9 +123,9 @@ config ACPI_BUTTON
        default y
        help
          This driver handles events on the power, sleep, and lid buttons.
-         A daemon reads /proc/acpi/event and perform user-defined actions
-         such as shutting down the system.  This is necessary for
-         software-controlled poweroff.
+         A daemon reads events from input devices or via netlink and
+         performs user-defined actions such as shutting down the system.
+         This is necessary for software-controlled poweroff.
 
          To compile this driver as a module, choose M here:
          the module will be called button.
index f40acef80269fa9e6a38435b1c328a7c80552b34..a6977e12d5745ab5f2015e2f2879174bddd64bc0 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/ipmi.h>
 #include <linux/device.h>
 #include <linux/pnp.h>
+#include <linux/spinlock.h>
 
 MODULE_AUTHOR("Zhao Yakui");
 MODULE_DESCRIPTION("ACPI IPMI Opregion driver");
@@ -57,7 +58,7 @@ struct acpi_ipmi_device {
        struct list_head head;
        /* the IPMI request message list */
        struct list_head tx_msg_list;
-       struct mutex    tx_msg_lock;
+       spinlock_t      tx_msg_lock;
        acpi_handle handle;
        struct pnp_dev *pnp_dev;
        ipmi_user_t     user_interface;
@@ -147,6 +148,7 @@ static void acpi_format_ipmi_msg(struct acpi_ipmi_msg *tx_msg,
        struct kernel_ipmi_msg *msg;
        struct acpi_ipmi_buffer *buffer;
        struct acpi_ipmi_device *device;
+       unsigned long flags;
 
        msg = &tx_msg->tx_message;
        /*
@@ -177,10 +179,10 @@ static void acpi_format_ipmi_msg(struct acpi_ipmi_msg *tx_msg,
 
        /* Get the msgid */
        device = tx_msg->device;
-       mutex_lock(&device->tx_msg_lock);
+       spin_lock_irqsave(&device->tx_msg_lock, flags);
        device->curr_msgid++;
        tx_msg->tx_msgid = device->curr_msgid;
-       mutex_unlock(&device->tx_msg_lock);
+       spin_unlock_irqrestore(&device->tx_msg_lock, flags);
 }
 
 static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg,
@@ -242,6 +244,7 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
        int msg_found = 0;
        struct acpi_ipmi_msg *tx_msg;
        struct pnp_dev *pnp_dev = ipmi_device->pnp_dev;
+       unsigned long flags;
 
        if (msg->user != ipmi_device->user_interface) {
                dev_warn(&pnp_dev->dev, "Unexpected response is returned. "
@@ -250,7 +253,7 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
                ipmi_free_recv_msg(msg);
                return;
        }
-       mutex_lock(&ipmi_device->tx_msg_lock);
+       spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags);
        list_for_each_entry(tx_msg, &ipmi_device->tx_msg_list, head) {
                if (msg->msgid == tx_msg->tx_msgid) {
                        msg_found = 1;
@@ -258,7 +261,7 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
                }
        }
 
-       mutex_unlock(&ipmi_device->tx_msg_lock);
+       spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags);
        if (!msg_found) {
                dev_warn(&pnp_dev->dev, "Unexpected response (msg id %ld) is "
                        "returned.\n", msg->msgid);
@@ -378,6 +381,7 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
        struct acpi_ipmi_device *ipmi_device = handler_context;
        int err, rem_time;
        acpi_status status;
+       unsigned long flags;
        /*
         * IPMI opregion message.
         * IPMI message is firstly written to the BMC and system software
@@ -395,9 +399,9 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
                return AE_NO_MEMORY;
 
        acpi_format_ipmi_msg(tx_msg, address, value);
-       mutex_lock(&ipmi_device->tx_msg_lock);
+       spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags);
        list_add_tail(&tx_msg->head, &ipmi_device->tx_msg_list);
-       mutex_unlock(&ipmi_device->tx_msg_lock);
+       spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags);
        err = ipmi_request_settime(ipmi_device->user_interface,
                                        &tx_msg->addr,
                                        tx_msg->tx_msgid,
@@ -413,9 +417,9 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
        status = AE_OK;
 
 end_label:
-       mutex_lock(&ipmi_device->tx_msg_lock);
+       spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags);
        list_del(&tx_msg->head);
-       mutex_unlock(&ipmi_device->tx_msg_lock);
+       spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags);
        kfree(tx_msg);
        return status;
 }
@@ -457,7 +461,7 @@ static void acpi_add_ipmi_device(struct acpi_ipmi_device *ipmi_device)
 
        INIT_LIST_HEAD(&ipmi_device->head);
 
-       mutex_init(&ipmi_device->tx_msg_lock);
+       spin_lock_init(&ipmi_device->tx_msg_lock);
        INIT_LIST_HEAD(&ipmi_device->tx_msg_list);
        ipmi_install_space_handler(ipmi_device);
 
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 59d3202f6b36fc197afe259b343764cb2a9621aa..a94383d1f3502ae35138e7e677df02c1d8df3d72 100644 (file)
@@ -1025,60 +1025,4 @@ void acpi_dev_pm_detach(struct device *dev, bool power_off)
        }
 }
 EXPORT_SYMBOL_GPL(acpi_dev_pm_detach);
-
-/**
- * acpi_dev_pm_add_dependent - Add physical device depending for PM.
- * @handle: Handle of ACPI device node.
- * @depdev: Device depending on that node for PM.
- */
-void acpi_dev_pm_add_dependent(acpi_handle handle, struct device *depdev)
-{
-       struct acpi_device_physical_node *dep;
-       struct acpi_device *adev;
-
-       if (!depdev || acpi_bus_get_device(handle, &adev))
-               return;
-
-       mutex_lock(&adev->physical_node_lock);
-
-       list_for_each_entry(dep, &adev->power_dependent, node)
-               if (dep->dev == depdev)
-                       goto out;
-
-       dep = kzalloc(sizeof(*dep), GFP_KERNEL);
-       if (dep) {
-               dep->dev = depdev;
-               list_add_tail(&dep->node, &adev->power_dependent);
-       }
-
- out:
-       mutex_unlock(&adev->physical_node_lock);
-}
-EXPORT_SYMBOL_GPL(acpi_dev_pm_add_dependent);
-
-/**
- * acpi_dev_pm_remove_dependent - Remove physical device depending for PM.
- * @handle: Handle of ACPI device node.
- * @depdev: Device depending on that node for PM.
- */
-void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev)
-{
-       struct acpi_device_physical_node *dep;
-       struct acpi_device *adev;
-
-       if (!depdev || acpi_bus_get_device(handle, &adev))
-               return;
-
-       mutex_lock(&adev->physical_node_lock);
-
-       list_for_each_entry(dep, &adev->power_dependent, node)
-               if (dep->dev == depdev) {
-                       list_del(&dep->node);
-                       kfree(dep);
-                       break;
-               }
-
-       mutex_unlock(&adev->physical_node_lock);
-}
-EXPORT_SYMBOL_GPL(acpi_dev_pm_remove_dependent);
 #endif /* CONFIG_PM */
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 0dbe5cdf3396e5f53b23c84bb30041329544774d..c2ad391d8041ecb6a354e2df07b9d813d817a744 100644 (file)
@@ -59,16 +59,9 @@ ACPI_MODULE_NAME("power");
 #define ACPI_POWER_RESOURCE_STATE_ON   0x01
 #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
 
-struct acpi_power_dependent_device {
-       struct list_head node;
-       struct acpi_device *adev;
-       struct work_struct work;
-};
-
 struct acpi_power_resource {
        struct acpi_device device;
        struct list_head list_node;
-       struct list_head dependent;
        char *name;
        u32 system_level;
        u32 order;
@@ -233,32 +226,6 @@ static int acpi_power_get_list_state(struct list_head *list, int *state)
        return 0;
 }
 
-static void acpi_power_resume_dependent(struct work_struct *work)
-{
-       struct acpi_power_dependent_device *dep;
-       struct acpi_device_physical_node *pn;
-       struct acpi_device *adev;
-       int state;
-
-       dep = container_of(work, struct acpi_power_dependent_device, work);
-       adev = dep->adev;
-       if (acpi_power_get_inferred_state(adev, &state))
-               return;
-
-       if (state > ACPI_STATE_D0)
-               return;
-
-       mutex_lock(&adev->physical_node_lock);
-
-       list_for_each_entry(pn, &adev->physical_node_list, node)
-               pm_request_resume(pn->dev);
-
-       list_for_each_entry(pn, &adev->power_dependent, node)
-               pm_request_resume(pn->dev);
-
-       mutex_unlock(&adev->physical_node_lock);
-}
-
 static int __acpi_power_on(struct acpi_power_resource *resource)
 {
        acpi_status status = AE_OK;
@@ -283,14 +250,8 @@ static int acpi_power_on_unlocked(struct acpi_power_resource *resource)
                                  resource->name));
        } else {
                result = __acpi_power_on(resource);
-               if (result) {
+               if (result)
                        resource->ref_count--;
-               } else {
-                       struct acpi_power_dependent_device *dep;
-
-                       list_for_each_entry(dep, &resource->dependent, node)
-                               schedule_work(&dep->work);
-               }
        }
        return result;
 }
@@ -390,52 +351,6 @@ static int acpi_power_on_list(struct list_head *list)
        return result;
 }
 
-static void acpi_power_add_dependent(struct acpi_power_resource *resource,
-                                    struct acpi_device *adev)
-{
-       struct acpi_power_dependent_device *dep;
-
-       mutex_lock(&resource->resource_lock);
-
-       list_for_each_entry(dep, &resource->dependent, node)
-               if (dep->adev == adev)
-                       goto out;
-
-       dep = kzalloc(sizeof(*dep), GFP_KERNEL);
-       if (!dep)
-               goto out;
-
-       dep->adev = adev;
-       INIT_WORK(&dep->work, acpi_power_resume_dependent);
-       list_add_tail(&dep->node, &resource->dependent);
-
- out:
-       mutex_unlock(&resource->resource_lock);
-}
-
-static void acpi_power_remove_dependent(struct acpi_power_resource *resource,
-                                       struct acpi_device *adev)
-{
-       struct acpi_power_dependent_device *dep;
-       struct work_struct *work = NULL;
-
-       mutex_lock(&resource->resource_lock);
-
-       list_for_each_entry(dep, &resource->dependent, node)
-               if (dep->adev == adev) {
-                       list_del(&dep->node);
-                       work = &dep->work;
-                       break;
-               }
-
-       mutex_unlock(&resource->resource_lock);
-
-       if (work) {
-               cancel_work_sync(work);
-               kfree(dep);
-       }
-}
-
 static struct attribute *attrs[] = {
        NULL,
 };
@@ -524,8 +439,6 @@ static void acpi_power_expose_hide(struct acpi_device *adev,
 
 void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
 {
-       struct acpi_device_power_state *ps;
-       struct acpi_power_resource_entry *entry;
        int state;
 
        if (adev->wakeup.flags.valid)
@@ -535,16 +448,6 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
        if (!adev->power.flags.power_resources)
                return;
 
-       ps = &adev->power.states[ACPI_STATE_D0];
-       list_for_each_entry(entry, &ps->resources, node) {
-               struct acpi_power_resource *resource = entry->resource;
-
-               if (add)
-                       acpi_power_add_dependent(resource, adev);
-               else
-                       acpi_power_remove_dependent(resource, adev);
-       }
-
        for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++)
                acpi_power_expose_hide(adev,
                                       &adev->power.states[state].resources,
@@ -882,7 +785,6 @@ int acpi_add_power_resource(acpi_handle handle)
        acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER,
                                ACPI_STA_DEFAULT);
        mutex_init(&resource->resource_lock);
-       INIT_LIST_HEAD(&resource->dependent);
        INIT_LIST_HEAD(&resource->list_node);
        resource->name = device->pnp.bus_id;
        strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
@@ -936,8 +838,10 @@ void acpi_resume_power_resources(void)
                mutex_lock(&resource->resource_lock);
 
                result = acpi_power_get_state(resource->device.handle, &state);
-               if (result)
+               if (result) {
+                       mutex_unlock(&resource->resource_lock);
                        continue;
+               }
 
                if (state == ACPI_POWER_RESOURCE_STATE_OFF
                    && resource->ref_count) {
index 61d090b6ce254007047aaaeaac2620fdcef60951..fee8a297c7d95310caa64492b75e6c2fae0c280e 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);
@@ -971,7 +968,7 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
        }
        return 0;
 }
-EXPORT_SYMBOL_GPL(acpi_bus_get_device);
+EXPORT_SYMBOL(acpi_bus_get_device);
 
 int acpi_device_add(struct acpi_device *device,
                    void (*release)(struct device *))
@@ -1002,7 +999,6 @@ int acpi_device_add(struct acpi_device *device,
        INIT_LIST_HEAD(&device->wakeup_list);
        INIT_LIST_HEAD(&device->physical_node_list);
        mutex_init(&device->physical_node_lock);
-       INIT_LIST_HEAD(&device->power_dependent);
 
        new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
        if (!new_bus_id) {
@@ -1124,7 +1120,7 @@ int acpi_bus_register_driver(struct acpi_driver *driver)
 EXPORT_SYMBOL(acpi_bus_register_driver);
 
 /**
- * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
+ * acpi_bus_unregister_driver - unregisters a driver with the ACPI bus
  * @driver: driver to unregister
  *
  * Unregisters a driver with the ACPI bus.  Searches the namespace for all
index 9d715ae5ff6b73b6bd09690b95e9686f196e9cdb..8e28f923cf7f3a221104eb625e4d3a89b5ab79ca 100644 (file)
@@ -1343,7 +1343,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
                host->flags |= ATA_HOST_PARALLEL_SCAN;
        else
-               printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
+               dev_info(&pdev->dev, "SSS flag set, parallel bus scan disabled\n");
 
        if (pi.flags & ATA_FLAG_EM)
                ahci_reset_em(host);
index 2daaee05cab12d629502c913ef7102a793cdf27f..7d3b85385bfc16b92ffe303acf38f343331dfc2e 100644 (file)
@@ -184,7 +184,7 @@ static int ahci_probe(struct platform_device *pdev)
        if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
                host->flags |= ATA_HOST_PARALLEL_SCAN;
        else
-               printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
+               dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
 
        if (pi.flags & ATA_FLAG_EM)
                ahci_reset_em(host);
index acfd0f711069e9da304c95179b14127e20ae1c9c..aaac4fb0d5645f8d52782fc55cb6f39da04830e7 100644 (file)
@@ -778,8 +778,16 @@ static void ahci_start_port(struct ata_port *ap)
                                rc = ap->ops->transmit_led_message(ap,
                                                               emp->led_state,
                                                               4);
+                               /*
+                                * If busy, give a breather but do not
+                                * release EH ownership by using msleep()
+                                * instead of ata_msleep().  EM Transmit
+                                * bit is busy for the whole host and
+                                * releasing ownership will cause other
+                                * ports to fail the same way.
+                                */
                                if (rc == -EBUSY)
-                                       ata_msleep(ap, 1);
+                                       msleep(1);
                                else
                                        break;
                        }
index 4ba8b04055728d49a0ac147a608d1ad27391d62a..ab714d2ad978644752ca3c9bdff74ae1c9f63934 100644 (file)
@@ -1035,17 +1035,3 @@ void ata_acpi_on_disable(struct ata_device *dev)
 {
        ata_acpi_clear_gtf(dev);
 }
-
-void ata_scsi_acpi_bind(struct ata_device *dev)
-{
-       acpi_handle handle = ata_dev_acpi_handle(dev);
-       if (handle)
-               acpi_dev_pm_add_dependent(handle, &dev->sdev->sdev_gendev);
-}
-
-void ata_scsi_acpi_unbind(struct ata_device *dev)
-{
-       acpi_handle handle = ata_dev_acpi_handle(dev);
-       if (handle)
-               acpi_dev_pm_remove_dependent(handle, &dev->sdev->sdev_gendev);
-}
index c69fcce505c03d06c7b20ae333ff9708a228f869..370462fa8e01addd3387befee8f4ea78486b2cc0 100644 (file)
@@ -1322,14 +1322,14 @@ void ata_eh_qc_complete(struct ata_queued_cmd *qc)
  *     should be retried.  To be used from EH.
  *
  *     SCSI midlayer limits the number of retries to scmd->allowed.
- *     scmd->retries is decremented for commands which get retried
+ *     scmd->allowed is incremented for commands which get retried
  *     due to unrelated failures (qc->err_mask is zero).
  */
 void ata_eh_qc_retry(struct ata_queued_cmd *qc)
 {
        struct scsi_cmnd *scmd = qc->scsicmd;
-       if (!qc->err_mask && scmd->retries)
-               scmd->retries--;
+       if (!qc->err_mask)
+               scmd->allowed++;
        __ata_eh_qc_complete(qc);
 }
 
index 97a0cef1295916223202058b83e80a20de74c7de..db6dfcfa3e2ee932190069290814f2a71bc8f3f6 100644 (file)
@@ -3679,7 +3679,6 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
                        if (!IS_ERR(sdev)) {
                                dev->sdev = sdev;
                                scsi_device_put(sdev);
-                               ata_scsi_acpi_bind(dev);
                        } else {
                                dev->sdev = NULL;
                        }
@@ -3767,8 +3766,6 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
        struct scsi_device *sdev;
        unsigned long flags;
 
-       ata_scsi_acpi_unbind(dev);
-
        /* Alas, we need to grab scan_mutex to ensure SCSI device
         * state doesn't change underneath us and thus
         * scsi_device_get() always succeeds.  The mutex locking can
index eeeb77845d48574e3f43b4b6e456302e5f3926d9..45b5ab3a95d51158c9ef0e618d6c8ae0fdeb373b 100644 (file)
@@ -121,8 +121,6 @@ extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state);
 extern void ata_acpi_bind_port(struct ata_port *ap);
 extern void ata_acpi_bind_dev(struct ata_device *dev);
 extern acpi_handle ata_dev_acpi_handle(struct ata_device *dev);
-extern void ata_scsi_acpi_bind(struct ata_device *dev);
-extern void ata_scsi_acpi_unbind(struct ata_device *dev);
 #else
 static inline void ata_acpi_dissociate(struct ata_host *host) { }
 static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
@@ -133,8 +131,6 @@ static inline void ata_acpi_set_state(struct ata_port *ap,
                                      pm_message_t state) { }
 static inline void ata_acpi_bind_port(struct ata_port *ap) {}
 static inline void ata_acpi_bind_dev(struct ata_device *dev) {}
-static inline void ata_scsi_acpi_bind(struct ata_device *dev) {}
-static inline void ata_scsi_acpi_unbind(struct ata_device *dev) {}
 #endif
 
 /* libata-scsi.c */
index 4bceb8803a10f50baee31c9c39233282ebbc6e91..b33d1f99b3a44bb40e76a529a8eddbc2268bdc20 100644 (file)
@@ -78,7 +78,7 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
 
        ap->ioaddr.cmd_addr = cmd_addr;
 
-       if (pnp_port_valid(idev, 1) == 0) {
+       if (pnp_port_valid(idev, 1)) {
                ctl_addr = devm_ioport_map(&idev->dev,
                                           pnp_port_start(idev, 1), 1);
                ap->ioaddr.altstatus_addr = ctl_addr;
index 958ba2a420c34b0e5411b116d639214e700f5c47..97f4acb54ad626795972ffb8e35572101d05d08d 100644 (file)
@@ -2,7 +2,7 @@
  *  sata_promise.c - Promise SATA
  *
  *  Maintained by:  Tejun Heo <tj@kernel.org>
- *                 Mikael Pettersson <mikpe@it.uu.se>
+ *                 Mikael Pettersson
  *                 Please ALWAYS copy linux-ide@vger.kernel.org
  *                 on emails.
  *
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 c7cfadcf67521d82f7d977979631e4805f5a31e9..34abf4d8a45ff4f3f6d25787887a8bc787779133 100644 (file)
@@ -2017,7 +2017,7 @@ EXPORT_SYMBOL_GPL(device_move);
  */
 void device_shutdown(void)
 {
-       struct device *dev;
+       struct device *dev, *parent;
 
        spin_lock(&devices_kset->list_lock);
        /*
@@ -2034,7 +2034,7 @@ void device_shutdown(void)
                 * prevent it from being freed because parent's
                 * lock is to be held
                 */
-               get_device(dev->parent);
+               parent = get_device(dev->parent);
                get_device(dev);
                /*
                 * Make sure the device is off the kset list, in the
@@ -2044,8 +2044,8 @@ void device_shutdown(void)
                spin_unlock(&devices_kset->list_lock);
 
                /* hold lock to avoid race with probe/release */
-               if (dev->parent)
-                       device_lock(dev->parent);
+               if (parent)
+                       device_lock(parent);
                device_lock(dev);
 
                /* Don't allow any more runtime suspends */
@@ -2063,11 +2063,11 @@ void device_shutdown(void)
                }
 
                device_unlock(dev);
-               if (dev->parent)
-                       device_unlock(dev->parent);
+               if (parent)
+                       device_unlock(parent);
 
                put_device(dev);
-               put_device(dev->parent);
+               put_device(parent);
 
                spin_lock(&devices_kset->list_lock);
        }
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 9e59f6535c442bbb26d6ad055b93a4b0cf5bef5d..bece691cb5d99d79f761b9400eebf1e9a78c55a2 100644 (file)
@@ -333,8 +333,10 @@ store_mem_state(struct device *dev,
                online_type = ONLINE_KEEP;
        else if (!strncmp(buf, "offline", min_t(int, count, 7)))
                online_type = -1;
-       else
-               return -EINVAL;
+       else {
+               ret = -EINVAL;
+               goto err;
+       }
 
        switch (online_type) {
        case ONLINE_KERNEL:
@@ -357,6 +359,7 @@ store_mem_state(struct device *dev,
                ret = -EINVAL; /* should never happen */
        }
 
+err:
        unlock_device_hotplug();
 
        if (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 c9fd6943ce456a1123e58106b0f028418d535fdd..50329d1057ed5dc5c929fde89237add36c55ea48 100644 (file)
@@ -210,25 +210,6 @@ static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
        }
 }
 
-static void bcma_core_pci_power_save(struct bcma_drv_pci *pc, bool up)
-{
-       u16 data;
-
-       if (pc->core->id.rev >= 15 && pc->core->id.rev <= 20) {
-               data = up ? 0x74 : 0x7C;
-               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
-                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7F64);
-               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
-                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
-       } else if (pc->core->id.rev >= 21 && pc->core->id.rev <= 22) {
-               data = up ? 0x75 : 0x7D;
-               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
-                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7E65);
-               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
-                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
-       }
-}
-
 /**************************************************
  * Init.
  **************************************************/
@@ -255,6 +236,32 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc)
                bcma_core_pci_clientmode_init(pc);
 }
 
+void bcma_core_pci_power_save(struct bcma_bus *bus, bool up)
+{
+       struct bcma_drv_pci *pc;
+       u16 data;
+
+       if (bus->hosttype != BCMA_HOSTTYPE_PCI)
+               return;
+
+       pc = &bus->drv_pci[0];
+
+       if (pc->core->id.rev >= 15 && pc->core->id.rev <= 20) {
+               data = up ? 0x74 : 0x7C;
+               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
+                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7F64);
+               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
+                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
+       } else if (pc->core->id.rev >= 21 && pc->core->id.rev <= 22) {
+               data = up ? 0x75 : 0x7D;
+               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
+                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7E65);
+               bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
+                                        BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
+       }
+}
+EXPORT_SYMBOL_GPL(bcma_core_pci_power_save);
+
 int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
                          bool enable)
 {
@@ -310,8 +317,6 @@ void bcma_core_pci_up(struct bcma_bus *bus)
 
        pc = &bus->drv_pci[0];
 
-       bcma_core_pci_power_save(pc, true);
-
        bcma_core_pci_extend_L1timer(pc, true);
 }
 EXPORT_SYMBOL_GPL(bcma_core_pci_up);
@@ -326,7 +331,5 @@ void bcma_core_pci_down(struct bcma_bus *bus)
        pc = &bus->drv_pci[0];
 
        bcma_core_pci_extend_L1timer(pc, false);
-
-       bcma_core_pci_power_save(pc, false);
 }
 EXPORT_SYMBOL_GPL(bcma_core_pci_down);
index cd6b20fce680591a5253f15546cae34d21a4bb68..37768401d1139f0cfa73ed3e6210ce892a5e91cc 100644 (file)
@@ -269,6 +269,8 @@ static struct bcma_device *bcma_find_core_reverse(struct bcma_bus *bus, u16 core
        return NULL;
 }
 
+#define IS_ERR_VALUE_U32(x) ((x) >= (u32)-MAX_ERRNO)
+
 static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                              struct bcma_device_id *match, int core_num,
                              struct bcma_device *core)
@@ -351,11 +353,11 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
         * the main register space for the core
         */
        tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
-       if (tmp == 0 || IS_ERR_VALUE(tmp)) {
+       if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
                /* Try again to see if it is a bridge */
                tmp = bcma_erom_get_addr_desc(bus, eromptr,
                                              SCAN_ADDR_TYPE_BRIDGE, 0);
-               if (tmp == 0 || IS_ERR_VALUE(tmp)) {
+               if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
                        return -EILSEQ;
                } else {
                        bcma_info(bus, "Bridge found\n");
@@ -369,7 +371,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                for (j = 0; ; j++) {
                        tmp = bcma_erom_get_addr_desc(bus, eromptr,
                                SCAN_ADDR_TYPE_SLAVE, i);
-                       if (IS_ERR_VALUE(tmp)) {
+                       if (IS_ERR_VALUE_U32(tmp)) {
                                /* no more entries for port _i_ */
                                /* pr_debug("erom: slave port %d "
                                 * "has %d descriptors\n", i, j); */
@@ -386,7 +388,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                for (j = 0; ; j++) {
                        tmp = bcma_erom_get_addr_desc(bus, eromptr,
                                SCAN_ADDR_TYPE_MWRAP, i);
-                       if (IS_ERR_VALUE(tmp)) {
+                       if (IS_ERR_VALUE_U32(tmp)) {
                                /* no more entries for port _i_ */
                                /* pr_debug("erom: master wrapper %d "
                                 * "has %d descriptors\n", i, j); */
@@ -404,7 +406,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                for (j = 0; ; j++) {
                        tmp = bcma_erom_get_addr_desc(bus, eromptr,
                                SCAN_ADDR_TYPE_SWRAP, i + hack);
-                       if (IS_ERR_VALUE(tmp)) {
+                       if (IS_ERR_VALUE_U32(tmp)) {
                                /* no more entries for port _i_ */
                                /* pr_debug("erom: master wrapper %d "
                                 * has %d descriptors\n", i, j); */
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..edfa2515bc8613f952c448194bfcebf7835d75c1 100644 (file)
@@ -1189,6 +1189,7 @@ static int cciss_ioctl32_passthru(struct block_device *bdev, fmode_t mode,
        int err;
        u32 cp;
 
+       memset(&arg64, 0, sizeof(arg64));
        err = 0;
        err |=
            copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
@@ -4257,6 +4258,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 639d26b90b9117a56c69f991663f603847cc206c..2b944038453681ef15ba61f41e1cfa3a9e885fbe 100644 (file)
@@ -1193,6 +1193,7 @@ out_passthru:
                ida_pci_info_struct pciinfo;
 
                if (!arg) return -EINVAL;
+               memset(&pciinfo, 0, sizeof(pciinfo));
                pciinfo.bus = host->pci_dev->bus->number;
                pciinfo.dev_fn = host->pci_dev->devfn;
                pciinfo.board_id = host->board_id;
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 a12b923bbaca91f14b923e0b271b00ebc1be8d28..0a327f4154a2b2039ad4ae0e50b7195dfa2cb5f0 100644 (file)
@@ -85,6 +85,7 @@ static struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x04CA, 0x3008) },
        { USB_DEVICE(0x13d3, 0x3362) },
        { USB_DEVICE(0x0CF3, 0xE004) },
+       { USB_DEVICE(0x0CF3, 0xE005) },
        { USB_DEVICE(0x0930, 0x0219) },
        { USB_DEVICE(0x0489, 0xe057) },
        { USB_DEVICE(0x13d3, 0x3393) },
@@ -126,6 +127,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
index 8e16f0af6358872606fbe102bddc9ade2c6ab470..f3dfc0a88fdcb95e25647caa6cfc14a1d9a5a484 100644 (file)
@@ -102,6 +102,7 @@ static struct usb_device_id btusb_table[] = {
 
        /* Broadcom BCM20702A0 */
        { USB_DEVICE(0x0b05, 0x17b5) },
+       { USB_DEVICE(0x0b05, 0x17cb) },
        { USB_DEVICE(0x04ca, 0x2003) },
        { USB_DEVICE(0x0489, 0xe042) },
        { USB_DEVICE(0x413c, 0x8197) },
@@ -112,6 +113,9 @@ static struct usb_device_id btusb_table[] = {
        /*Broadcom devices with vendor specific id */
        { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
 
+       /* Belkin F8065bf - Broadcom based */
+       { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
+
        { }     /* Terminating entry */
 };
 
@@ -148,6 +152,7 @@ static struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
index 19ab6ff53d59776cedc592a5b18c2fba8fe02a65..2394e9753ef56b47e93d91bd7499eeb657c51383 100644 (file)
@@ -700,6 +700,7 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
                                         phys_addr_t sdramwins_phys_base,
                                         size_t sdramwins_size)
 {
+       struct device_node *np;
        int win;
 
        mbus->mbuswins_base = ioremap(mbuswins_phys_base, mbuswins_size);
@@ -712,8 +713,11 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
                return -ENOMEM;
        }
 
-       if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"))
+       np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
+       if (np) {
                mbus->hw_io_coherency = 1;
+               of_node_put(np);
+       }
 
        for (win = 0; win < mbus->soc->num_wins; win++)
                mvebu_mbus_disable_window(mbus, win);
@@ -861,11 +865,13 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np,
        int ret;
 
        /*
-        * These are optional, so we clear them and they'll
-        * be zero if they are missing from the DT.
+        * These are optional, so we make sure that resource_size(x) will
+        * return 0.
         */
        memset(mem, 0, sizeof(struct resource));
+       mem->end = -1;
        memset(io, 0, sizeof(struct resource));
+       io->end = -1;
 
        ret = of_property_read_u32_array(np, "pcie-mem-aperture", reg, ARRAY_SIZE(reg));
        if (!ret) {
index 40a865449f35bf80a7b035ed02a6904c3767b674..0aa9d91daef500486e999c8ce4ccb4cb90d2755d 100644 (file)
@@ -153,12 +153,12 @@ config HW_RANDOM_IXP4XX
 
 config HW_RANDOM_OMAP
        tristate "OMAP Random Number Generator support"
-       depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP2)
+       depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP2PLUS)
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
-         Generator hardware found on OMAP16xx and OMAP24xx multimedia
-         processors.
+         Generator hardware found on OMAP16xx, OMAP2/3/4/5 and AM33xx/AM43xx
+         multimedia processors.
 
          To compile this driver as a module, choose M here: the
          module will be called omap-rng.
index 19a12ac64a9ec966149286a84a2f0db5e3e0ee60..6a86b6f56af22c08810acdeb861f2599549f2827 100644 (file)
@@ -164,7 +164,9 @@ static int __init mxc_rnga_probe(struct platform_device *pdev)
                goto out;
        }
 
-       clk_prepare_enable(mxc_rng->clk);
+       err = clk_prepare_enable(mxc_rng->clk);
+       if (err)
+               goto out;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        mxc_rng->mem = devm_ioremap_resource(&pdev->dev, res);
index 6843ec87b98b9f87b3a6ebc3736335d6884826ff..9b89ff4881de7cdfe49e607e33c5ed0788f0be58 100644 (file)
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/interrupt.h>
 
 #include <asm/io.h>
 
-#define RNG_OUT_REG            0x00            /* Output register */
-#define RNG_STAT_REG           0x04            /* Status register
-                                                       [0] = STAT_BUSY */
-#define RNG_ALARM_REG          0x24            /* Alarm register
-                                                       [7:0] = ALARM_COUNTER */
-#define RNG_CONFIG_REG         0x28            /* Configuration register
-                                                       [11:6] = RESET_COUNT
-                                                       [5:3]  = RING2_DELAY
-                                                       [2:0]  = RING1_DELAY */
-#define RNG_REV_REG            0x3c            /* Revision register
-                                                       [7:0] = REV_NB */
-#define RNG_MASK_REG           0x40            /* Mask and reset register
-                                                       [2] = IT_EN
-                                                       [1] = SOFTRESET
-                                                       [0] = AUTOIDLE */
-#define RNG_SYSSTATUS          0x44            /* System status
-                                                       [0] = RESETDONE */
+#define RNG_REG_STATUS_RDY                     (1 << 0)
+
+#define RNG_REG_INTACK_RDY_MASK                        (1 << 0)
+#define RNG_REG_INTACK_SHUTDOWN_OFLO_MASK      (1 << 1)
+#define RNG_SHUTDOWN_OFLO_MASK                 (1 << 1)
+
+#define RNG_CONTROL_STARTUP_CYCLES_SHIFT       16
+#define RNG_CONTROL_STARTUP_CYCLES_MASK                (0xffff << 16)
+#define RNG_CONTROL_ENABLE_TRNG_SHIFT          10
+#define RNG_CONTROL_ENABLE_TRNG_MASK           (1 << 10)
+
+#define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT      16
+#define RNG_CONFIG_MAX_REFIL_CYCLES_MASK       (0xffff << 16)
+#define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT      0
+#define RNG_CONFIG_MIN_REFIL_CYCLES_MASK       (0xff << 0)
+
+#define RNG_CONTROL_STARTUP_CYCLES             0xff
+#define RNG_CONFIG_MIN_REFIL_CYCLES            0x21
+#define RNG_CONFIG_MAX_REFIL_CYCLES            0x22
+
+#define RNG_ALARMCNT_ALARM_TH_SHIFT            0x0
+#define RNG_ALARMCNT_ALARM_TH_MASK             (0xff << 0)
+#define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT         16
+#define RNG_ALARMCNT_SHUTDOWN_TH_MASK          (0x1f << 16)
+#define RNG_ALARM_THRESHOLD                    0xff
+#define RNG_SHUTDOWN_THRESHOLD                 0x4
+
+#define RNG_REG_FROENABLE_MASK                 0xffffff
+#define RNG_REG_FRODETUNE_MASK                 0xffffff
+
+#define OMAP2_RNG_OUTPUT_SIZE                  0x4
+#define OMAP4_RNG_OUTPUT_SIZE                  0x8
+
+enum {
+       RNG_OUTPUT_L_REG = 0,
+       RNG_OUTPUT_H_REG,
+       RNG_STATUS_REG,
+       RNG_INTMASK_REG,
+       RNG_INTACK_REG,
+       RNG_CONTROL_REG,
+       RNG_CONFIG_REG,
+       RNG_ALARMCNT_REG,
+       RNG_FROENABLE_REG,
+       RNG_FRODETUNE_REG,
+       RNG_ALARMMASK_REG,
+       RNG_ALARMSTOP_REG,
+       RNG_REV_REG,
+       RNG_SYSCONFIG_REG,
+};
+
+static const u16 reg_map_omap2[] = {
+       [RNG_OUTPUT_L_REG]      = 0x0,
+       [RNG_STATUS_REG]        = 0x4,
+       [RNG_CONFIG_REG]        = 0x28,
+       [RNG_REV_REG]           = 0x3c,
+       [RNG_SYSCONFIG_REG]     = 0x40,
+};
 
+static const u16 reg_map_omap4[] = {
+       [RNG_OUTPUT_L_REG]      = 0x0,
+       [RNG_OUTPUT_H_REG]      = 0x4,
+       [RNG_STATUS_REG]        = 0x8,
+       [RNG_INTMASK_REG]       = 0xc,
+       [RNG_INTACK_REG]        = 0x10,
+       [RNG_CONTROL_REG]       = 0x14,
+       [RNG_CONFIG_REG]        = 0x18,
+       [RNG_ALARMCNT_REG]      = 0x1c,
+       [RNG_FROENABLE_REG]     = 0x20,
+       [RNG_FRODETUNE_REG]     = 0x24,
+       [RNG_ALARMMASK_REG]     = 0x28,
+       [RNG_ALARMSTOP_REG]     = 0x2c,
+       [RNG_REV_REG]           = 0x1FE0,
+       [RNG_SYSCONFIG_REG]     = 0x1FE4,
+};
+
+struct omap_rng_dev;
 /**
- * struct omap_rng_private_data - RNG IP block-specific data
- * @base: virtual address of the beginning of the RNG IP block registers
- * @mem_res: struct resource * for the IP block registers physical memory
+ * struct omap_rng_pdata - RNG IP block-specific data
+ * @regs: Pointer to the register offsets structure.
+ * @data_size: No. of bytes in RNG output.
+ * @data_present: Callback to determine if data is available.
+ * @init: Callback for IP specific initialization sequence.
+ * @cleanup: Callback for IP specific cleanup sequence.
  */
-struct omap_rng_private_data {
-       void __iomem *base;
-       struct resource *mem_res;
+struct omap_rng_pdata {
+       u16     *regs;
+       u32     data_size;
+       u32     (*data_present)(struct omap_rng_dev *priv);
+       int     (*init)(struct omap_rng_dev *priv);
+       void    (*cleanup)(struct omap_rng_dev *priv);
 };
 
-static inline u32 omap_rng_read_reg(struct omap_rng_private_data *priv, int reg)
+struct omap_rng_dev {
+       void __iomem                    *base;
+       struct device                   *dev;
+       const struct omap_rng_pdata     *pdata;
+};
+
+static inline u32 omap_rng_read(struct omap_rng_dev *priv, u16 reg)
 {
-       return __raw_readl(priv->base + reg);
+       return __raw_readl(priv->base + priv->pdata->regs[reg]);
 }
 
-static inline void omap_rng_write_reg(struct omap_rng_private_data *priv,
-                                     int reg, u32 val)
+static inline void omap_rng_write(struct omap_rng_dev *priv, u16 reg,
+                                     u32 val)
 {
-       __raw_writel(val, priv->base + reg);
+       __raw_writel(val, priv->base + priv->pdata->regs[reg]);
 }
 
 static int omap_rng_data_present(struct hwrng *rng, int wait)
 {
-       struct omap_rng_private_data *priv;
+       struct omap_rng_dev *priv;
        int data, i;
 
-       priv = (struct omap_rng_private_data *)rng->priv;
+       priv = (struct omap_rng_dev *)rng->priv;
 
        for (i = 0; i < 20; i++) {
-               data = omap_rng_read_reg(priv, RNG_STAT_REG) ? 0 : 1;
+               data = priv->pdata->data_present(priv);
                if (data || !wait)
                        break;
                /* RNG produces data fast enough (2+ MBit/sec, even
@@ -89,27 +163,212 @@ static int omap_rng_data_present(struct hwrng *rng, int wait)
 
 static int omap_rng_data_read(struct hwrng *rng, u32 *data)
 {
-       struct omap_rng_private_data *priv;
+       struct omap_rng_dev *priv;
+       u32 data_size, i;
+
+       priv = (struct omap_rng_dev *)rng->priv;
+       data_size = priv->pdata->data_size;
+
+       for (i = 0; i < data_size / sizeof(u32); i++)
+               data[i] = omap_rng_read(priv, RNG_OUTPUT_L_REG + i);
+
+       if (priv->pdata->regs[RNG_INTACK_REG])
+               omap_rng_write(priv, RNG_INTACK_REG, RNG_REG_INTACK_RDY_MASK);
+       return data_size;
+}
+
+static int omap_rng_init(struct hwrng *rng)
+{
+       struct omap_rng_dev *priv;
 
-       priv = (struct omap_rng_private_data *)rng->priv;
+       priv = (struct omap_rng_dev *)rng->priv;
+       return priv->pdata->init(priv);
+}
 
-       *data = omap_rng_read_reg(priv, RNG_OUT_REG);
+static void omap_rng_cleanup(struct hwrng *rng)
+{
+       struct omap_rng_dev *priv;
 
-       return sizeof(u32);
+       priv = (struct omap_rng_dev *)rng->priv;
+       priv->pdata->cleanup(priv);
 }
 
 static struct hwrng omap_rng_ops = {
        .name           = "omap",
        .data_present   = omap_rng_data_present,
        .data_read      = omap_rng_data_read,
+       .init           = omap_rng_init,
+       .cleanup        = omap_rng_cleanup,
+};
+
+static inline u32 omap2_rng_data_present(struct omap_rng_dev *priv)
+{
+       return omap_rng_read(priv, RNG_STATUS_REG) ? 0 : 1;
+}
+
+static int omap2_rng_init(struct omap_rng_dev *priv)
+{
+       omap_rng_write(priv, RNG_SYSCONFIG_REG, 0x1);
+       return 0;
+}
+
+static void omap2_rng_cleanup(struct omap_rng_dev *priv)
+{
+       omap_rng_write(priv, RNG_SYSCONFIG_REG, 0x0);
+}
+
+static struct omap_rng_pdata omap2_rng_pdata = {
+       .regs           = (u16 *)reg_map_omap2,
+       .data_size      = OMAP2_RNG_OUTPUT_SIZE,
+       .data_present   = omap2_rng_data_present,
+       .init           = omap2_rng_init,
+       .cleanup        = omap2_rng_cleanup,
 };
 
+#if defined(CONFIG_OF)
+static inline u32 omap4_rng_data_present(struct omap_rng_dev *priv)
+{
+       return omap_rng_read(priv, RNG_STATUS_REG) & RNG_REG_STATUS_RDY;
+}
+
+static int omap4_rng_init(struct omap_rng_dev *priv)
+{
+       u32 val;
+
+       /* Return if RNG is already running. */
+       if (omap_rng_read(priv, RNG_CONFIG_REG) & RNG_CONTROL_ENABLE_TRNG_MASK)
+               return 0;
+
+       val = RNG_CONFIG_MIN_REFIL_CYCLES << RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT;
+       val |= RNG_CONFIG_MAX_REFIL_CYCLES << RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT;
+       omap_rng_write(priv, RNG_CONFIG_REG, val);
+
+       omap_rng_write(priv, RNG_FRODETUNE_REG, 0x0);
+       omap_rng_write(priv, RNG_FROENABLE_REG, RNG_REG_FROENABLE_MASK);
+       val = RNG_ALARM_THRESHOLD << RNG_ALARMCNT_ALARM_TH_SHIFT;
+       val |= RNG_SHUTDOWN_THRESHOLD << RNG_ALARMCNT_SHUTDOWN_TH_SHIFT;
+       omap_rng_write(priv, RNG_ALARMCNT_REG, val);
+
+       val = RNG_CONTROL_STARTUP_CYCLES << RNG_CONTROL_STARTUP_CYCLES_SHIFT;
+       val |= RNG_CONTROL_ENABLE_TRNG_MASK;
+       omap_rng_write(priv, RNG_CONTROL_REG, val);
+
+       return 0;
+}
+
+static void omap4_rng_cleanup(struct omap_rng_dev *priv)
+{
+       int val;
+
+       val = omap_rng_read(priv, RNG_CONTROL_REG);
+       val &= ~RNG_CONTROL_ENABLE_TRNG_MASK;
+       omap_rng_write(priv, RNG_CONFIG_REG, val);
+}
+
+static irqreturn_t omap4_rng_irq(int irq, void *dev_id)
+{
+       struct omap_rng_dev *priv = dev_id;
+       u32 fro_detune, fro_enable;
+
+       /*
+        * Interrupt raised by a fro shutdown threshold, do the following:
+        * 1. Clear the alarm events.
+        * 2. De tune the FROs which are shutdown.
+        * 3. Re enable the shutdown FROs.
+        */
+       omap_rng_write(priv, RNG_ALARMMASK_REG, 0x0);
+       omap_rng_write(priv, RNG_ALARMSTOP_REG, 0x0);
+
+       fro_enable = omap_rng_read(priv, RNG_FROENABLE_REG);
+       fro_detune = ~fro_enable & RNG_REG_FRODETUNE_MASK;
+       fro_detune = fro_detune | omap_rng_read(priv, RNG_FRODETUNE_REG);
+       fro_enable = RNG_REG_FROENABLE_MASK;
+
+       omap_rng_write(priv, RNG_FRODETUNE_REG, fro_detune);
+       omap_rng_write(priv, RNG_FROENABLE_REG, fro_enable);
+
+       omap_rng_write(priv, RNG_INTACK_REG, RNG_REG_INTACK_SHUTDOWN_OFLO_MASK);
+
+       return IRQ_HANDLED;
+}
+
+static struct omap_rng_pdata omap4_rng_pdata = {
+       .regs           = (u16 *)reg_map_omap4,
+       .data_size      = OMAP4_RNG_OUTPUT_SIZE,
+       .data_present   = omap4_rng_data_present,
+       .init           = omap4_rng_init,
+       .cleanup        = omap4_rng_cleanup,
+};
+
+static const struct of_device_id omap_rng_of_match[] = {
+               {
+                       .compatible     = "ti,omap2-rng",
+                       .data           = &omap2_rng_pdata,
+               },
+               {
+                       .compatible     = "ti,omap4-rng",
+                       .data           = &omap4_rng_pdata,
+               },
+               {},
+};
+MODULE_DEVICE_TABLE(of, omap_rng_of_match);
+
+static int of_get_omap_rng_device_details(struct omap_rng_dev *priv,
+                                         struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       struct device *dev = &pdev->dev;
+       int irq, err;
+
+       match = of_match_device(of_match_ptr(omap_rng_of_match), dev);
+       if (!match) {
+               dev_err(dev, "no compatible OF match\n");
+               return -EINVAL;
+       }
+       priv->pdata = match->data;
+
+       if (of_device_is_compatible(dev->of_node, "ti,omap4-rng")) {
+               irq = platform_get_irq(pdev, 0);
+               if (irq < 0) {
+                       dev_err(dev, "%s: error getting IRQ resource - %d\n",
+                               __func__, irq);
+                       return irq;
+               }
+
+               err = devm_request_irq(dev, irq, omap4_rng_irq,
+                                      IRQF_TRIGGER_NONE, dev_name(dev), priv);
+               if (err) {
+                       dev_err(dev, "unable to request irq %d, err = %d\n",
+                               irq, err);
+                       return err;
+               }
+               omap_rng_write(priv, RNG_INTMASK_REG, RNG_SHUTDOWN_OFLO_MASK);
+       }
+       return 0;
+}
+#else
+static int of_get_omap_rng_device_details(struct omap_rng_dev *omap_rng,
+                                         struct platform_device *pdev)
+{
+       return -EINVAL;
+}
+#endif
+
+static int get_omap_rng_device_details(struct omap_rng_dev *omap_rng)
+{
+       /* Only OMAP2/3 can be non-DT */
+       omap_rng->pdata = &omap2_rng_pdata;
+       return 0;
+}
+
 static int omap_rng_probe(struct platform_device *pdev)
 {
-       struct omap_rng_private_data *priv;
+       struct omap_rng_dev *priv;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
        int ret;
 
-       priv = kzalloc(sizeof(struct omap_rng_private_data), GFP_KERNEL);
+       priv = devm_kzalloc(dev, sizeof(struct omap_rng_dev), GFP_KERNEL);
        if (!priv) {
                dev_err(&pdev->dev, "could not allocate memory\n");
                return -ENOMEM;
@@ -117,26 +376,29 @@ static int omap_rng_probe(struct platform_device *pdev)
 
        omap_rng_ops.priv = (unsigned long)priv;
        platform_set_drvdata(pdev, priv);
+       priv->dev = dev;
 
-       priv->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->base = devm_ioremap_resource(&pdev->dev, priv->mem_res);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->base = devm_ioremap_resource(dev, res);
        if (IS_ERR(priv->base)) {
                ret = PTR_ERR(priv->base);
                goto err_ioremap;
        }
-       platform_set_drvdata(pdev, priv);
 
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
 
+       ret = (dev->of_node) ? of_get_omap_rng_device_details(priv, pdev) :
+                               get_omap_rng_device_details(priv);
+       if (ret)
+               goto err_ioremap;
+
        ret = hwrng_register(&omap_rng_ops);
        if (ret)
                goto err_register;
 
        dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n",
-                omap_rng_read_reg(priv, RNG_REV_REG));
-
-       omap_rng_write_reg(priv, RNG_MASK_REG, 0x1);
+                omap_rng_read(priv, RNG_REV_REG));
 
        return 0;
 
@@ -144,26 +406,21 @@ err_register:
        priv->base = NULL;
        pm_runtime_disable(&pdev->dev);
 err_ioremap:
-       kfree(priv);
-
+       dev_err(dev, "initialization failed.\n");
        return ret;
 }
 
 static int __exit omap_rng_remove(struct platform_device *pdev)
 {
-       struct omap_rng_private_data *priv = platform_get_drvdata(pdev);
+       struct omap_rng_dev *priv = platform_get_drvdata(pdev);
 
        hwrng_unregister(&omap_rng_ops);
 
-       omap_rng_write_reg(priv, RNG_MASK_REG, 0x0);
+       priv->pdata->cleanup(priv);
 
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
-       release_mem_region(priv->mem_res->start, resource_size(priv->mem_res));
-
-       kfree(priv);
-
        return 0;
 }
 
@@ -171,9 +428,9 @@ static int __exit omap_rng_remove(struct platform_device *pdev)
 
 static int omap_rng_suspend(struct device *dev)
 {
-       struct omap_rng_private_data *priv = dev_get_drvdata(dev);
+       struct omap_rng_dev *priv = dev_get_drvdata(dev);
 
-       omap_rng_write_reg(priv, RNG_MASK_REG, 0x0);
+       priv->pdata->cleanup(priv);
        pm_runtime_put_sync(dev);
 
        return 0;
@@ -181,10 +438,10 @@ static int omap_rng_suspend(struct device *dev)
 
 static int omap_rng_resume(struct device *dev)
 {
-       struct omap_rng_private_data *priv = dev_get_drvdata(dev);
+       struct omap_rng_dev *priv = dev_get_drvdata(dev);
 
        pm_runtime_get_sync(dev);
-       omap_rng_write_reg(priv, RNG_MASK_REG, 0x1);
+       priv->pdata->init(priv);
 
        return 0;
 }
@@ -198,31 +455,18 @@ static SIMPLE_DEV_PM_OPS(omap_rng_pm, omap_rng_suspend, omap_rng_resume);
 
 #endif
 
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:omap_rng");
-
 static struct platform_driver omap_rng_driver = {
        .driver = {
                .name           = "omap_rng",
                .owner          = THIS_MODULE,
                .pm             = OMAP_RNG_PM,
+               .of_match_table = of_match_ptr(omap_rng_of_match),
        },
        .probe          = omap_rng_probe,
        .remove         = __exit_p(omap_rng_remove),
 };
 
-static int __init omap_rng_init(void)
-{
-       return platform_driver_register(&omap_rng_driver);
-}
-
-static void __exit omap_rng_exit(void)
-{
-       platform_driver_unregister(&omap_rng_driver);
-}
-
-module_init(omap_rng_init);
-module_exit(omap_rng_exit);
-
+module_platform_driver(omap_rng_driver);
+MODULE_ALIAS("platform:omap_rng");
 MODULE_AUTHOR("Deepak Saxena (and others)");
 MODULE_LICENSE("GPL");
index 973b95113edf7580e09bcb078db0038c047dd7f6..3d4c2293c6f560d239691ba26ab3d7ee241e38f0 100644 (file)
@@ -33,7 +33,7 @@
 
 static void __iomem *rng_base;
 static struct clk *rng_clk;
-struct device *rng_dev;
+static struct device *rng_dev;
 
 static inline u32 picoxcell_trng_read_csr(void)
 {
index 00593c847cf0b1d63875d44a26e1159461bce885..09c5fbea2b9304e4282ef9365d5f372ff6b49e0a 100644 (file)
@@ -110,12 +110,10 @@ static int __init tx4939_rng_probe(struct platform_device *dev)
        struct resource *r;
        int i;
 
-       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!r)
-               return -EBUSY;
        rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL);
        if (!rngdev)
                return -ENOMEM;
+       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
        rngdev->base = devm_ioremap_resource(&dev->dev, r);
        if (IS_ERR(rngdev->base))
                return PTR_ERR(rngdev->base);
index d0387a84eec1363ff40a05854ecaf48f51f63701..e737772ad69a8103312e596cd0e24ce00d759e22 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/kernel.h>
 #include <linux/hw_random.h>
 #include <linux/delay.h>
+#include <asm/cpu_device_id.h>
 #include <asm/io.h>
 #include <asm/msr.h>
 #include <asm/cpufeature.h>
@@ -220,5 +221,11 @@ static void __exit mod_exit(void)
 module_init(mod_init);
 module_exit(mod_exit);
 
+static struct x86_cpu_id via_rng_cpu_id[] = {
+       X86_FEATURE_MATCH(X86_FEATURE_XSTORE),
+       {}
+};
+
 MODULE_DESCRIPTION("H/W RNG driver for VIA CPU with PadLock");
 MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(x86cpu, via_rng_cpu_id);
index 0d91fe52f3f5eee10397563361a4b1dd1579e8cf..7a744d39175638a381835a8cadce7039f58ee3bf 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>
@@ -643,7 +640,7 @@ struct timer_rand_state {
  */
 void add_device_randomness(const void *buf, unsigned int size)
 {
-       unsigned long time = get_cycles() ^ jiffies;
+       unsigned long time = random_get_entropy() ^ jiffies;
 
        mix_pool_bytes(&input_pool, buf, size, NULL);
        mix_pool_bytes(&input_pool, &time, sizeof(time), NULL);
@@ -680,7 +677,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
                goto out;
 
        sample.jiffies = jiffies;
-       sample.cycles = get_cycles();
+       sample.cycles = random_get_entropy();
        sample.num = num;
        mix_pool_bytes(&input_pool, &sample, sizeof(sample), NULL);
 
@@ -747,7 +744,7 @@ void add_interrupt_randomness(int irq, int irq_flags)
        struct fast_pool        *fast_pool = &__get_cpu_var(irq_randomness);
        struct pt_regs          *regs = get_irq_regs();
        unsigned long           now = jiffies;
-       __u32                   input[4], cycles = get_cycles();
+       __u32                   input[4], cycles = random_get_entropy();
 
        input[0] = cycles ^ jiffies;
        input[1] = irq;
@@ -1462,12 +1459,11 @@ struct ctl_table random_table[] = {
 
 static u32 random_int_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
 
-static int __init random_int_secret_init(void)
+int random_int_secret_init(void)
 {
        get_random_bytes(random_int_secret, sizeof(random_int_secret));
        return 0;
 }
-late_initcall(random_int_secret_init);
 
 /*
  * Get a random word for internal kernel use only. Similar to urandom but
@@ -1486,7 +1482,7 @@ unsigned int get_random_int(void)
 
        hash = get_cpu_var(get_random_int_hash);
 
-       hash[0] += current->pid + jiffies + get_cycles();
+       hash[0] += current->pid + jiffies + random_get_entropy();
        md5_transform(hash, random_int_secret);
        ret = hash[0];
        put_cpu_var(get_random_int_hash);
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 7a7929ba26588dbf07d014bf8bb3cf8f55da509a..94c280d36e8b3bfaea00ee36c4fe3215818b3c86 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
+#include <xen/xen.h>
 #include <xen/events.h>
 #include <xen/interface/io/tpmif.h>
 #include <xen/grant_table.h>
@@ -142,32 +143,6 @@ static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
        return length;
 }
 
-ssize_t tpm_show_locality(struct device *dev, struct device_attribute *attr,
-                         char *buf)
-{
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       struct tpm_private *priv = TPM_VPRIV(chip);
-       u8 locality = priv->shr->locality;
-
-       return sprintf(buf, "%d\n", locality);
-}
-
-ssize_t tpm_store_locality(struct device *dev, struct device_attribute *attr,
-                       const char *buf, size_t len)
-{
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-       struct tpm_private *priv = TPM_VPRIV(chip);
-       u8 val;
-
-       int rv = kstrtou8(buf, 0, &val);
-       if (rv)
-               return rv;
-
-       priv->shr->locality = val;
-
-       return len;
-}
-
 static const struct file_operations vtpm_ops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
@@ -188,8 +163,6 @@ static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
 static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
 static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
 static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
-static DEVICE_ATTR(locality, S_IRUGO | S_IWUSR, tpm_show_locality,
-               tpm_store_locality);
 
 static struct attribute *vtpm_attrs[] = {
        &dev_attr_pubek.attr,
@@ -202,7 +175,6 @@ static struct attribute *vtpm_attrs[] = {
        &dev_attr_cancel.attr,
        &dev_attr_durations.attr,
        &dev_attr_timeouts.attr,
-       &dev_attr_locality.attr,
        NULL,
 };
 
@@ -210,8 +182,6 @@ static struct attribute_group vtpm_attr_grp = {
        .attrs = vtpm_attrs,
 };
 
-#define TPM_LONG_TIMEOUT   (10 * 60 * HZ)
-
 static const struct tpm_vendor_specific tpm_vtpm = {
        .status = vtpm_status,
        .recv = vtpm_recv,
@@ -224,11 +194,6 @@ static const struct tpm_vendor_specific tpm_vtpm = {
        .miscdev = {
                .fops = &vtpm_ops,
        },
-       .duration = {
-               TPM_LONG_TIMEOUT,
-               TPM_LONG_TIMEOUT,
-               TPM_LONG_TIMEOUT,
-       },
 };
 
 static irqreturn_t tpmif_interrupt(int dummy, void *dev_id)
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 41c69469ce2000ec223170970c856a2287f10db2..971d796e071d889c290029ada3b2dc862f10fcbb 100644 (file)
@@ -26,6 +26,7 @@ config DW_APB_TIMER_OF
 
 config ARMADA_370_XP_TIMER
        bool
+       select CLKSRC_OF
 
 config ORION_TIMER
        select CLKSRC_OF
index 37f5325bec95936260c50b2a099ccc7fb000ba53..b9ddd9e3a2f599e2cc7424c1eac18d4280b2f850 100644 (file)
@@ -30,6 +30,9 @@ void __init clocksource_of_init(void)
        clocksource_of_init_fn init_func;
 
        for_each_matching_node_and_match(np, __clksrc_of_table, &match) {
+               if (!of_device_is_available(np))
+                       continue;
+
                init_func = match->data;
                init_func(np);
        }
index 4329a29a5310d046eaedc12cd14229791c6e14f1..3a5909c12d420dbbb6f54f011882303ba4a48a62 100644 (file)
@@ -301,7 +301,7 @@ static void em_sti_register_clockevent(struct em_sti_priv *p)
        ced->name = dev_name(&p->pdev->dev);
        ced->features = CLOCK_EVT_FEAT_ONESHOT;
        ced->rating = 200;
-       ced->cpumask = cpumask_of(0);
+       ced->cpumask = cpu_possible_mask;
        ced->set_next_event = em_sti_clock_event_next;
        ced->set_mode = em_sti_clock_event_mode;
 
@@ -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 5b34768f4d7c79f68253966acc8e8268e53f318e..62b0de6a18370fade34eca20205557bd5871cc3a 100644 (file)
@@ -428,7 +428,6 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt)
                                evt->irq);
                        return -EIO;
                }
-               irq_set_affinity(evt->irq, cpumask_of(cpu));
        } else {
                enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0);
        }
@@ -449,6 +448,7 @@ static int exynos4_mct_cpu_notify(struct notifier_block *self,
                                           unsigned long action, void *hcpu)
 {
        struct mct_clock_event_device *mevt;
+       unsigned int cpu;
 
        /*
         * Grab cpu pointer in each case to avoid spurious
@@ -459,6 +459,12 @@ static int exynos4_mct_cpu_notify(struct notifier_block *self,
                mevt = this_cpu_ptr(&percpu_mct_tick);
                exynos4_local_timer_setup(&mevt->evt);
                break;
+       case CPU_ONLINE:
+               cpu = (unsigned long)hcpu;
+               if (mct_int_type == MCT_INT_SPI)
+                       irq_set_affinity(mct_irqs[MCT_L0_IRQ + cpu],
+                                               cpumask_of(cpu));
+               break;
        case CPU_DYING:
                mevt = this_cpu_ptr(&percpu_mct_tick);
                exynos4_local_timer_stop(&mevt->evt);
@@ -500,6 +506,8 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem
                                         &percpu_mct_tick);
                WARN(err, "MCT: can't request IRQ %d (%d)\n",
                     mct_irqs[MCT_L0_IRQ], err);
+       } else {
+               irq_set_affinity(mct_irqs[MCT_L0_IRQ], cpumask_of(0));
        }
 
        err = register_cpu_notifier(&exynos4_mct_cpu_nb);
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 a1260b4549db647336192d24b3471b6b627897af..d2c3253e015ee23f107d2d34333c6afa533ab7cf 100644 (file)
@@ -986,6 +986,10 @@ static int __init acpi_cpufreq_init(void)
 {
        int ret;
 
+       /* don't keep reloading if cpufreq_driver exists */
+       if (cpufreq_get_current_driver())
+               return 0;
+
        if (acpi_disabled)
                return 0;
 
index cbfffa91ebdd46054d21f5c4138909b549787b06..c522a95c0e168ae30e4a347f189f89c27173c427 100644 (file)
@@ -12,6 +12,7 @@
 #define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
 
 #include <linux/clk.h>
+#include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/err.h>
 #include <linux/module.h>
@@ -177,7 +178,11 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
        struct device_node *np;
        int ret;
 
-       cpu_dev = &pdev->dev;
+       cpu_dev = get_cpu_device(0);
+       if (!cpu_dev) {
+               pr_err("failed to get cpu0 device\n");
+               return -ENODEV;
+       }
 
        np = of_node_get(cpu_dev->of_node);
        if (!np) {
@@ -224,7 +229,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
        if (of_property_read_u32(np, "clock-latency", &transition_latency))
                transition_latency = CPUFREQ_ETERNAL;
 
-       if (cpu_reg) {
+       if (!IS_ERR(cpu_reg)) {
                struct opp *opp;
                unsigned long min_uV, max_uV;
                int i;
index 5c75e3147a607ca70a6d880500f9a9b6fb336316..04548f7023af68dee6b36fc590ec59f02c0216f7 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,32 @@ 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;
+
+       /*
+        * Take direct locks as lock_policy_rwsem_write wouldn't work here.
+        * Also lock for last cpu is enough here as contention will happen only
+        * after policy->cpu is changed and after it is changed, other threads
+        * will try to acquire lock for new cpu. And policy is already updated
+        * by then.
+        */
+       down_write(&per_cpu(cpu_policy_rwsem, policy->cpu));
+
+       policy->last_cpu = policy->cpu;
+       policy->cpu = cpu;
+
+       up_write(&per_cpu(cpu_policy_rwsem, policy->last_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 +1026,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 +1129,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)
 {
@@ -1117,7 +1136,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
        int ret;
 
        /* first sibling now owns the new sysfs dir */
-       cpu_dev = get_cpu_device(cpumask_first(policy->cpus));
+       cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu));
 
        /* Don't touch sysfs files during light-weight tear-down */
        if (frozen)
@@ -1141,22 +1160,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);
 
@@ -1189,22 +1200,18 @@ static int __cpufreq_remove_dev(struct device *dev,
                        policy->governor->name, CPUFREQ_NAME_LEN);
 #endif
 
-       WARN_ON(lock_policy_rwsem_write(cpu));
+       lock_policy_rwsem_read(cpu);
        cpus = cpumask_weight(policy->cpus);
+       unlock_policy_rwsem_read(cpu);
 
-       if (cpus > 1)
-               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);
                if (new_cpu >= 0) {
-                       WARN_ON(lock_policy_rwsem_write(cpu));
                        update_policy_cpu(policy, new_cpu);
-                       unlock_policy_rwsem_write(cpu);
 
                        if (!frozen) {
                                pr_debug("%s: policy Kobject moved to cpu: %d "
@@ -1213,6 +1220,36 @@ 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;
+       }
+
+       WARN_ON(lock_policy_rwsem_write(cpu));
+       cpus = cpumask_weight(policy->cpus);
+
+       if (cpus > 1)
+               cpumask_clear_cpu(cpu, policy->cpus);
+       unlock_policy_rwsem_write(cpu);
+
        /* If cpu is last user of policy, free policy */
        if (cpus == 1) {
                if (cpufreq_driver->target) {
@@ -1272,6 +1309,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;
@@ -1402,6 +1460,9 @@ unsigned int cpufreq_get(unsigned int cpu)
 {
        unsigned int ret_freq = 0;
 
+       if (cpufreq_disabled() || !cpufreq_driver)
+               return -ENOENT;
+
        if (!down_read_trylock(&cpufreq_rwsem))
                return 0;
 
@@ -1610,8 +1671,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 +1751,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 +2054,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:
@@ -2043,7 +2107,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
        write_lock_irqsave(&cpufreq_driver_lock, flags);
        if (cpufreq_driver) {
                write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-               return -EBUSY;
+               return -EEXIST;
        }
        cpufreq_driver = driver_data;
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
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 d514c152fd1a43041e8ff570fca7f9cc2b28f58d..be5380ecdcd43f95c4aa88a62389c184597f3971 100644 (file)
@@ -457,7 +457,7 @@ err_free_table:
        opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
 err_put_node:
        of_node_put(np);
-       dev_err(dvfs_info->dev, "%s: failed initialization\n", __func__);
+       dev_err(&pdev->dev, "%s: failed initialization\n", __func__);
        return ret;
 }
 
index 3e396543aea4f74bb6b2d54e5a839eedf43a2c1a..c3fd2a101ca02852c677d021c567b27ee74b075a 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/delay.h>
 #include <linux/err.h>
@@ -202,7 +203,11 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
        unsigned long min_volt, max_volt;
        int num, ret;
 
-       cpu_dev = &pdev->dev;
+       cpu_dev = get_cpu_device(0);
+       if (!cpu_dev) {
+               pr_err("failed to get cpu0 device\n");
+               return -ENODEV;
+       }
 
        np = of_node_get(cpu_dev->of_node);
        if (!np) {
index 6efd96c196b2efff80e41b1851e4b445350ccf5b..badf6206b2b20d7284ffbbd098fd66676937fb64 100644 (file)
@@ -383,6 +383,7 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
 static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
 {
        int max_perf, min_perf;
+       u64 val;
 
        intel_pstate_get_min_max(cpu, &min_perf, &max_perf);
 
@@ -394,8 +395,11 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
        trace_cpu_frequency(pstate * 100000, cpu->cpu);
 
        cpu->pstate.current_pstate = pstate;
-       wrmsrl(MSR_IA32_PERF_CTL, pstate << 8);
+       val = pstate << 8;
+       if (limits.no_turbo)
+               val |= (u64)1 << 32;
 
+       wrmsrl(MSR_IA32_PERF_CTL, val);
 }
 
 static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps)
@@ -522,6 +526,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);
@@ -629,8 +638,8 @@ static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
 
 static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
 {
-       int rc, min_pstate, max_pstate;
        struct cpudata *cpu;
+       int rc;
 
        rc = intel_pstate_init_cpu(policy->cpu);
        if (rc)
@@ -644,9 +653,8 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
        else
                policy->policy = CPUFREQ_POLICY_POWERSAVE;
 
-       intel_pstate_get_min_max(cpu, &min_pstate, &max_pstate);
-       policy->min = min_pstate * 100000;
-       policy->max = max_pstate * 100000;
+       policy->min = cpu->pstate.min_pstate * 100000;
+       policy->max = cpu->pstate.turbo_pstate * 100000;
 
        /* cpuinfo and default policy values */
        policy->cpuinfo.min_freq = cpu->pstate.min_pstate * 100000;
index 8a72b0c555f846da21d25d02d9f94d427a7796b5..15631f92ab7d78cceec876e319c85092c921b8bc 100644 (file)
@@ -166,7 +166,7 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
                if (freq->frequency == CPUFREQ_ENTRY_INVALID)
                        continue;
 
-               dvfs = &s3c64xx_dvfs_table[freq->index];
+               dvfs = &s3c64xx_dvfs_table[freq->driver_data];
                found = 0;
 
                for (i = 0; i < count; i++) {
index 19e364fa59559cd6bf3e0ec77d9e5bb7c391aafa..3f418166ce02b8fc57a664f3d870bfb8508f3018 100644 (file)
@@ -113,7 +113,7 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
                unsigned int target_freq, unsigned int relation)
 {
        struct cpufreq_freqs freqs;
-       unsigned long newfreq;
+       long newfreq;
        struct clk *srcclk;
        int index, ret, mult = 1;
 
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 8ff7c230d82e487d9644c6c5c4552c228764074e..f4fd837bcb82a82530485f1f54a55dc75e362fdf 100644 (file)
@@ -242,17 +242,20 @@ config CRYPTO_DEV_PPC4XX
          This option allows you to have support for AMCC crypto acceleration.
 
 config CRYPTO_DEV_OMAP_SHAM
-       tristate "Support for OMAP SHA1/MD5 hw accelerator"
-       depends on ARCH_OMAP2 || ARCH_OMAP3
+       tristate "Support for OMAP MD5/SHA1/SHA2 hw accelerator"
+       depends on ARCH_OMAP2PLUS
        select CRYPTO_SHA1
        select CRYPTO_MD5
+       select CRYPTO_SHA256
+       select CRYPTO_SHA512
+       select CRYPTO_HMAC
        help
-         OMAP processors have SHA1/MD5 hw accelerator. Select this if you
-         want to use the OMAP module for SHA1/MD5 algorithms.
+         OMAP processors have MD5/SHA1/SHA2 hw accelerator. Select this if you
+         want to use the OMAP module for MD5/SHA1/SHA2 algorithms.
 
 config CRYPTO_DEV_OMAP_AES
        tristate "Support for OMAP AES hw engine"
-       depends on ARCH_OMAP2 || ARCH_OMAP3
+       depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP2PLUS
        select CRYPTO_AES
        select CRYPTO_BLKCIPHER2
        help
index a33243c17b00d0c3929fdd49693edc0524e06f8c..4afca396877335653ae8f6f902d1bcdf5b3b9db3 100644 (file)
 #include "crypto4xx_sa.h"
 #include "crypto4xx_core.h"
 
-void set_dynamic_sa_command_0(struct dynamic_sa_ctl *sa, u32 save_h,
-                             u32 save_iv, u32 ld_h, u32 ld_iv, u32 hdr_proc,
-                             u32 h, u32 c, u32 pad_type, u32 op_grp, u32 op,
-                             u32 dir)
+static void set_dynamic_sa_command_0(struct dynamic_sa_ctl *sa, u32 save_h,
+                                    u32 save_iv, u32 ld_h, u32 ld_iv,
+                                    u32 hdr_proc, u32 h, u32 c, u32 pad_type,
+                                    u32 op_grp, u32 op, u32 dir)
 {
        sa->sa_command_0.w = 0;
        sa->sa_command_0.bf.save_hash_state = save_h;
@@ -52,9 +52,10 @@ void set_dynamic_sa_command_0(struct dynamic_sa_ctl *sa, u32 save_h,
        sa->sa_command_0.bf.dir = dir;
 }
 
-void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm, u32 hmac_mc,
-                             u32 cfb, u32 esn, u32 sn_mask, u32 mute,
-                             u32 cp_pad, u32 cp_pay, u32 cp_hdr)
+static void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm,
+                                    u32 hmac_mc, u32 cfb, u32 esn,
+                                    u32 sn_mask, u32 mute, u32 cp_pad,
+                                    u32 cp_pay, u32 cp_hdr)
 {
        sa->sa_command_1.w = 0;
        sa->sa_command_1.bf.crypto_mode31 = (cm & 4) >> 2;
index b44091c47f752535b2eaf18fb4ad250b799695b2..ca89f6b84b068c1ecc770eededee50bf8c1d55aa 100644 (file)
@@ -98,3 +98,11 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API
 
          To compile this as a module, choose M here: the module
          will be called caamrng.
+
+config CRYPTO_DEV_FSL_CAAM_DEBUG
+       bool "Enable debug output in CAAM driver"
+       depends on CRYPTO_DEV_FSL_CAAM
+       default n
+       help
+         Selecting this will enable printing of various debug
+         information in the CAAM driver.
index b1eb44838db5644bc51dc5c2eff85929ff125aa6..d56bd0ec65d877ca9f2989ad77173214cc537868 100644 (file)
@@ -1,6 +1,9 @@
 #
 # Makefile for the CAAM backend and dependent components
 #
+ifeq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG), y)
+       EXTRA_CFLAGS := -DDEBUG
+endif
 
 obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o
 obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
index bf416a8391a77ec94dc3686d773e5afb7b437b3d..7c63b72ecd750f381fef66e8baccc7955351b1b3 100644 (file)
@@ -65,8 +65,6 @@
 #define CAAM_MAX_IV_LENGTH             16
 
 /* length of descriptors text */
-#define DESC_JOB_IO_LEN                        (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3)
-
 #define DESC_AEAD_BASE                 (4 * CAAM_CMD_SZ)
 #define DESC_AEAD_ENC_LEN              (DESC_AEAD_BASE + 16 * CAAM_CMD_SZ)
 #define DESC_AEAD_DEC_LEN              (DESC_AEAD_BASE + 21 * CAAM_CMD_SZ)
@@ -84,8 +82,6 @@
 
 #ifdef DEBUG
 /* for print_hex_dumps with line references */
-#define xstr(s) str(s)
-#define str(s) #s
 #define debug(format, arg...) printk(format, arg)
 #else
 #define debug(format, arg...)
@@ -285,7 +281,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
                return -ENOMEM;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "aead enc shdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "aead enc shdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc,
                       desc_bytes(desc), 1);
 #endif
@@ -353,7 +349,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
                return -ENOMEM;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "aead dec shdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "aead dec shdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc,
                       desc_bytes(desc), 1);
 #endif
@@ -436,7 +432,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
                return -ENOMEM;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "aead givenc shdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "aead givenc shdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc,
                       desc_bytes(desc), 1);
 #endif
@@ -500,7 +496,7 @@ static int aead_setkey(struct crypto_aead *aead,
               keylen, enckeylen, authkeylen);
        printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n",
               ctx->split_key_len, ctx->split_key_pad_len);
-       print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
 #endif
 
@@ -519,7 +515,7 @@ static int aead_setkey(struct crypto_aead *aead,
                return -ENOMEM;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
                       ctx->split_key_pad_len + enckeylen, 1);
 #endif
@@ -549,7 +545,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
        u32 *desc;
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
 #endif
 
@@ -598,7 +594,8 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
                return -ENOMEM;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ablkcipher enc shdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR,
+                      "ablkcipher enc shdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc,
                       desc_bytes(desc), 1);
 #endif
@@ -643,7 +640,8 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
        }
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ablkcipher dec shdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR,
+                      "ablkcipher dec shdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc,
                       desc_bytes(desc), 1);
 #endif
@@ -780,13 +778,13 @@ static void aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
        aead_unmap(jrdev, edesc, req);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "assoc  @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "assoc  @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->assoc),
                       req->assoclen , 1);
-       print_hex_dump(KERN_ERR, "dstiv  @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "dstiv  @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src) - ivsize,
                       edesc->src_nents ? 100 : ivsize, 1);
-       print_hex_dump(KERN_ERR, "dst    @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "dst    @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
                       edesc->src_nents ? 100 : req->cryptlen +
                       ctx->authsize + 4, 1);
@@ -814,10 +812,10 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
                 offsetof(struct aead_edesc, hw_desc));
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "dstiv  @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "dstiv  @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
                       ivsize, 1);
-       print_hex_dump(KERN_ERR, "dst    @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "dst    @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->dst),
                       req->cryptlen, 1);
 #endif
@@ -837,7 +835,7 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
                err = -EBADMSG;
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "iphdrout@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "iphdrout@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4,
                       ((char *)sg_virt(req->assoc) - sizeof(struct iphdr)),
                       sizeof(struct iphdr) + req->assoclen +
@@ -845,7 +843,7 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
                       ctx->authsize + 36, 1);
        if (!err && edesc->sec4_sg_bytes) {
                struct scatterlist *sg = sg_last(req->src, edesc->src_nents);
-               print_hex_dump(KERN_ERR, "sglastout@"xstr(__LINE__)": ",
+               print_hex_dump(KERN_ERR, "sglastout@"__stringify(__LINE__)": ",
                               DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(sg),
                        sg->length + ctx->authsize + 16, 1);
        }
@@ -878,10 +876,10 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
        }
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "dstiv  @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "dstiv  @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, req->info,
                       edesc->src_nents > 1 ? 100 : ivsize, 1);
-       print_hex_dump(KERN_ERR, "dst    @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "dst    @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
                       edesc->dst_nents > 1 ? 100 : req->nbytes, 1);
 #endif
@@ -913,10 +911,10 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
        }
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "dstiv  @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "dstiv  @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, req->info,
                       ivsize, 1);
-       print_hex_dump(KERN_ERR, "dst    @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "dst    @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
                       edesc->dst_nents > 1 ? 100 : req->nbytes, 1);
 #endif
@@ -947,16 +945,16 @@ static void init_aead_job(u32 *sh_desc, dma_addr_t ptr,
 #ifdef DEBUG
        debug("assoclen %d cryptlen %d authsize %d\n",
              req->assoclen, req->cryptlen, authsize);
-       print_hex_dump(KERN_ERR, "assoc  @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "assoc  @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->assoc),
                       req->assoclen , 1);
-       print_hex_dump(KERN_ERR, "presciv@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
                       edesc->src_nents ? 100 : ivsize, 1);
-       print_hex_dump(KERN_ERR, "src    @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "src    @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
                        edesc->src_nents ? 100 : req->cryptlen, 1);
-       print_hex_dump(KERN_ERR, "shrdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "shrdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sh_desc,
                       desc_bytes(sh_desc), 1);
 #endif
@@ -1025,15 +1023,15 @@ static void init_aead_giv_job(u32 *sh_desc, dma_addr_t ptr,
 #ifdef DEBUG
        debug("assoclen %d cryptlen %d authsize %d\n",
              req->assoclen, req->cryptlen, authsize);
-       print_hex_dump(KERN_ERR, "assoc  @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "assoc  @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->assoc),
                       req->assoclen , 1);
-       print_hex_dump(KERN_ERR, "presciv@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1);
-       print_hex_dump(KERN_ERR, "src    @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "src    @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
                        edesc->src_nents > 1 ? 100 : req->cryptlen, 1);
-       print_hex_dump(KERN_ERR, "shrdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "shrdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sh_desc,
                       desc_bytes(sh_desc), 1);
 #endif
@@ -1086,10 +1084,10 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr,
        int len, sec4_sg_index = 0;
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "presciv@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, req->info,
                       ivsize, 1);
-       print_hex_dump(KERN_ERR, "src    @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "src    @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
                       edesc->src_nents ? 100 : req->nbytes, 1);
 #endif
@@ -1247,7 +1245,7 @@ static int aead_encrypt(struct aead_request *req)
        init_aead_job(ctx->sh_desc_enc, ctx->sh_desc_enc_dma, edesc, req,
                      all_contig, true);
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "aead jobdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
                       desc_bytes(edesc->hw_desc), 1);
 #endif
@@ -1281,7 +1279,7 @@ static int aead_decrypt(struct aead_request *req)
                return PTR_ERR(edesc);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "dec src@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "dec src@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
                       req->cryptlen, 1);
 #endif
@@ -1290,7 +1288,7 @@ static int aead_decrypt(struct aead_request *req)
        init_aead_job(ctx->sh_desc_dec,
                      ctx->sh_desc_dec_dma, edesc, req, all_contig, false);
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "aead jobdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
                       desc_bytes(edesc->hw_desc), 1);
 #endif
@@ -1437,7 +1435,7 @@ static int aead_givencrypt(struct aead_givcrypt_request *areq)
                return PTR_ERR(edesc);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "giv src@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "giv src@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
                       req->cryptlen, 1);
 #endif
@@ -1446,7 +1444,7 @@ static int aead_givencrypt(struct aead_givcrypt_request *areq)
        init_aead_giv_job(ctx->sh_desc_givenc,
                          ctx->sh_desc_givenc_dma, edesc, req, contig);
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "aead jobdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
                       desc_bytes(edesc->hw_desc), 1);
 #endif
@@ -1546,7 +1544,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
        edesc->iv_dma = iv_dma;
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ablkcipher sec4_sg@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "ablkcipher sec4_sg@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg,
                       sec4_sg_bytes, 1);
 #endif
@@ -1575,7 +1573,7 @@ static int ablkcipher_encrypt(struct ablkcipher_request *req)
        init_ablkcipher_job(ctx->sh_desc_enc,
                ctx->sh_desc_enc_dma, edesc, req, iv_contig);
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
                       desc_bytes(edesc->hw_desc), 1);
 #endif
@@ -1613,7 +1611,7 @@ static int ablkcipher_decrypt(struct ablkcipher_request *req)
                ctx->sh_desc_dec_dma, edesc, req, iv_contig);
        desc = edesc->hw_desc;
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
                       desc_bytes(edesc->hw_desc), 1);
 #endif
index 84573b4d6f92809d5cd98fa968f6dd1a617482d3..e732bd962e98cc715db6463c7587dbb2511707e3 100644 (file)
@@ -72,8 +72,6 @@
 #define CAAM_MAX_HASH_DIGEST_SIZE      SHA512_DIGEST_SIZE
 
 /* length of descriptors text */
-#define DESC_JOB_IO_LEN                        (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3)
-
 #define DESC_AHASH_BASE                        (4 * CAAM_CMD_SZ)
 #define DESC_AHASH_UPDATE_LEN          (6 * CAAM_CMD_SZ)
 #define DESC_AHASH_UPDATE_FIRST_LEN    (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ)
@@ -91,8 +89,6 @@
 
 #ifdef DEBUG
 /* for print_hex_dumps with line references */
-#define xstr(s) str(s)
-#define str(s) #s
 #define debug(format, arg...) printk(format, arg)
 #else
 #define debug(format, arg...)
@@ -331,7 +327,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
                return -ENOMEM;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ahash update shdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR,
+                      "ahash update shdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
@@ -349,7 +346,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
                return -ENOMEM;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ahash update first shdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR,
+                      "ahash update first shdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
@@ -366,7 +364,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
                return -ENOMEM;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ahash final shdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "ahash final shdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc,
                       desc_bytes(desc), 1);
 #endif
@@ -384,7 +382,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
                return -ENOMEM;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ahash finup shdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "ahash finup shdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc,
                       desc_bytes(desc), 1);
 #endif
@@ -403,7 +401,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
                return -ENOMEM;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ahash digest shdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR,
+                      "ahash digest shdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc,
                       desc_bytes(desc), 1);
 #endif
@@ -464,9 +463,9 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in,
                         LDST_SRCDST_BYTE_CONTEXT);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "key_in@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "key_in@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, key_in, *keylen, 1);
-       print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
@@ -479,7 +478,8 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in,
                wait_for_completion_interruptible(&result.completion);
                ret = result.err;
 #ifdef DEBUG
-               print_hex_dump(KERN_ERR, "digested key@"xstr(__LINE__)": ",
+               print_hex_dump(KERN_ERR,
+                              "digested key@"__stringify(__LINE__)": ",
                               DUMP_PREFIX_ADDRESS, 16, 4, key_in,
                               digestsize, 1);
 #endif
@@ -530,7 +530,7 @@ static int ahash_setkey(struct crypto_ahash *ahash,
 #ifdef DEBUG
        printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n",
               ctx->split_key_len, ctx->split_key_pad_len);
-       print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
 #endif
 
@@ -545,7 +545,7 @@ static int ahash_setkey(struct crypto_ahash *ahash,
                return -ENOMEM;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
                       ctx->split_key_pad_len, 1);
 #endif
@@ -638,11 +638,11 @@ static void ahash_done(struct device *jrdev, u32 *desc, u32 err,
        kfree(edesc);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ctx@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
                       ctx->ctx_len, 1);
        if (req->result)
-               print_hex_dump(KERN_ERR, "result@"xstr(__LINE__)": ",
+               print_hex_dump(KERN_ERR, "result@"__stringify(__LINE__)": ",
                               DUMP_PREFIX_ADDRESS, 16, 4, req->result,
                               digestsize, 1);
 #endif
@@ -676,11 +676,11 @@ static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err,
        kfree(edesc);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ctx@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
                       ctx->ctx_len, 1);
        if (req->result)
-               print_hex_dump(KERN_ERR, "result@"xstr(__LINE__)": ",
+               print_hex_dump(KERN_ERR, "result@"__stringify(__LINE__)": ",
                               DUMP_PREFIX_ADDRESS, 16, 4, req->result,
                               digestsize, 1);
 #endif
@@ -714,11 +714,11 @@ static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err,
        kfree(edesc);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ctx@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
                       ctx->ctx_len, 1);
        if (req->result)
-               print_hex_dump(KERN_ERR, "result@"xstr(__LINE__)": ",
+               print_hex_dump(KERN_ERR, "result@"__stringify(__LINE__)": ",
                               DUMP_PREFIX_ADDRESS, 16, 4, req->result,
                               digestsize, 1);
 #endif
@@ -752,11 +752,11 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err,
        kfree(edesc);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ctx@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
                       ctx->ctx_len, 1);
        if (req->result)
-               print_hex_dump(KERN_ERR, "result@"xstr(__LINE__)": ",
+               print_hex_dump(KERN_ERR, "result@"__stringify(__LINE__)": ",
                               DUMP_PREFIX_ADDRESS, 16, 4, req->result,
                               digestsize, 1);
 #endif
@@ -852,7 +852,7 @@ static int ahash_update_ctx(struct ahash_request *req)
                append_seq_out_ptr(desc, state->ctx_dma, ctx->ctx_len, 0);
 
 #ifdef DEBUG
-               print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ",
+               print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
                               DUMP_PREFIX_ADDRESS, 16, 4, desc,
                               desc_bytes(desc), 1);
 #endif
@@ -871,9 +871,9 @@ static int ahash_update_ctx(struct ahash_request *req)
                *next_buflen = last_buflen;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "buf@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "buf@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
-       print_hex_dump(KERN_ERR, "next buf@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, next_buf,
                       *next_buflen, 1);
 #endif
@@ -937,7 +937,7 @@ static int ahash_final_ctx(struct ahash_request *req)
                                                digestsize);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
@@ -1016,7 +1016,7 @@ static int ahash_finup_ctx(struct ahash_request *req)
                                                digestsize);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
@@ -1086,7 +1086,7 @@ static int ahash_digest(struct ahash_request *req)
                                                digestsize);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
@@ -1140,7 +1140,7 @@ static int ahash_final_no_ctx(struct ahash_request *req)
        edesc->src_nents = 0;
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
@@ -1228,7 +1228,7 @@ static int ahash_update_no_ctx(struct ahash_request *req)
                map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len);
 
 #ifdef DEBUG
-               print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ",
+               print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
                               DUMP_PREFIX_ADDRESS, 16, 4, desc,
                               desc_bytes(desc), 1);
 #endif
@@ -1250,9 +1250,9 @@ static int ahash_update_no_ctx(struct ahash_request *req)
                *next_buflen = 0;
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "buf@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "buf@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
-       print_hex_dump(KERN_ERR, "next buf@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, next_buf,
                       *next_buflen, 1);
 #endif
@@ -1321,7 +1321,7 @@ static int ahash_finup_no_ctx(struct ahash_request *req)
                                                digestsize);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
@@ -1414,7 +1414,7 @@ static int ahash_update_first(struct ahash_request *req)
                map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len);
 
 #ifdef DEBUG
-               print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ",
+               print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
                               DUMP_PREFIX_ADDRESS, 16, 4, desc,
                               desc_bytes(desc), 1);
 #endif
@@ -1438,7 +1438,7 @@ static int ahash_update_first(struct ahash_request *req)
                sg_copy(next_buf, req->src, req->nbytes);
        }
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "next buf@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, next_buf,
                       *next_buflen, 1);
 #endif
index f5d6deced1cbaac0b00702e60aabdf0a9598c3b7..b010d42a18035fa48a8797dc802267f70db531d2 100644 (file)
@@ -75,55 +75,53 @@ static void build_instantiation_desc(u32 *desc)
                         OP_ALG_RNG4_SK);
 }
 
-struct instantiate_result {
-       struct completion completion;
-       int err;
-};
-
-static void rng4_init_done(struct device *dev, u32 *desc, u32 err,
-                          void *context)
-{
-       struct instantiate_result *instantiation = context;
-
-       if (err) {
-               char tmp[CAAM_ERROR_STR_MAX];
-
-               dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err));
-       }
-
-       instantiation->err = err;
-       complete(&instantiation->completion);
-}
-
-static int instantiate_rng(struct device *jrdev)
+static int instantiate_rng(struct device *ctrldev)
 {
-       struct instantiate_result instantiation;
-
-       dma_addr_t desc_dma;
+       struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
+       struct caam_full __iomem *topregs;
+       unsigned int timeout = 100000;
        u32 *desc;
-       int ret;
+       int i, ret = 0;
 
        desc = kmalloc(CAAM_CMD_SZ * 6, GFP_KERNEL | GFP_DMA);
        if (!desc) {
-               dev_err(jrdev, "cannot allocate RNG init descriptor memory\n");
+               dev_err(ctrldev, "can't allocate RNG init descriptor memory\n");
                return -ENOMEM;
        }
-
        build_instantiation_desc(desc);
-       desc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE);
-       init_completion(&instantiation.completion);
-       ret = caam_jr_enqueue(jrdev, desc, rng4_init_done, &instantiation);
-       if (!ret) {
-               wait_for_completion_interruptible(&instantiation.completion);
-               ret = instantiation.err;
-               if (ret)
-                       dev_err(jrdev, "unable to instantiate RNG\n");
+
+       /* Set the bit to request direct access to DECO0 */
+       topregs = (struct caam_full __iomem *)ctrlpriv->ctrl;
+       setbits32(&topregs->ctrl.deco_rq, DECORR_RQD0ENABLE);
+
+       while (!(rd_reg32(&topregs->ctrl.deco_rq) & DECORR_DEN0) &&
+                                                                --timeout)
+               cpu_relax();
+
+       if (!timeout) {
+               dev_err(ctrldev, "failed to acquire DECO 0\n");
+               ret = -EIO;
+               goto out;
        }
 
-       dma_unmap_single(jrdev, desc_dma, desc_bytes(desc), DMA_TO_DEVICE);
+       for (i = 0; i < desc_len(desc); i++)
+               topregs->deco.descbuf[i] = *(desc + i);
 
-       kfree(desc);
+       wr_reg32(&topregs->deco.jr_ctl_hi, DECO_JQCR_WHL | DECO_JQCR_FOUR);
 
+       timeout = 10000000;
+       while ((rd_reg32(&topregs->deco.desc_dbg) & DECO_DBG_VALID) &&
+                                                                --timeout)
+               cpu_relax();
+
+       if (!timeout) {
+               dev_err(ctrldev, "failed to instantiate RNG\n");
+               ret = -EIO;
+       }
+
+       clrbits32(&topregs->ctrl.deco_rq, DECORR_RQD0ENABLE);
+out:
+       kfree(desc);
        return ret;
 }
 
@@ -303,7 +301,7 @@ static int caam_probe(struct platform_device *pdev)
        if ((cha_vid & CHA_ID_RNG_MASK) >> CHA_ID_RNG_SHIFT >= 4 &&
            !(rd_reg32(&topregs->ctrl.r4tst[0].rdsta) & RDSTA_IF0)) {
                kick_trng(pdev);
-               ret = instantiate_rng(ctrlpriv->jrdev[0]);
+               ret = instantiate_rng(dev);
                if (ret) {
                        caam_remove(pdev);
                        return ret;
@@ -315,9 +313,6 @@ static int caam_probe(struct platform_device *pdev)
 
        /* NOTE: RTIC detection ought to go here, around Si time */
 
-       /* Initialize queue allocator lock */
-       spin_lock_init(&ctrlpriv->jr_alloc_lock);
-
        caam_id = rd_reg64(&topregs->ctrl.perfmon.caam_id);
 
        /* Report "alive" for developer to see */
index fe3bfd1b08cae14bf00c59ccddf9d026e9b2c717..cd5f678847ce3e7e93b1634a510bcd548abafe01 100644 (file)
@@ -10,6 +10,7 @@
 #define CAAM_CMD_SZ sizeof(u32)
 #define CAAM_PTR_SZ sizeof(dma_addr_t)
 #define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * MAX_CAAM_DESCSIZE)
+#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3)
 
 #ifdef DEBUG
 #define PRINT_POS do { printk(KERN_DEBUG "%02d: %s\n", desc_len(desc),\
index e4a16b741371d1df496d6344be5fc214896ba50c..34c4b9f7fbfae414a1578e37da245fd9119ac8fd 100644 (file)
@@ -9,9 +9,6 @@
 #ifndef INTERN_H
 #define INTERN_H
 
-#define JOBR_UNASSIGNED 0
-#define JOBR_ASSIGNED 1
-
 /* Currently comes from Kconfig param as a ^2 (driver-required) */
 #define JOBR_DEPTH (1 << CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE)
 
@@ -46,7 +43,6 @@ struct caam_drv_private_jr {
        struct caam_job_ring __iomem *rregs;    /* JobR's register space */
        struct tasklet_struct irqtask;
        int irq;                        /* One per queue */
-       int assign;                     /* busy/free */
 
        /* Job ring info */
        int ringsize;   /* Size of rings (assume input = output) */
@@ -68,7 +64,6 @@ struct caam_drv_private {
 
        struct device *dev;
        struct device **jrdev; /* Alloc'ed array per sub-device */
-       spinlock_t jr_alloc_lock;
        struct platform_device *pdev;
 
        /* Physical-presence section */
index b4aa773ecbc83ec7f61548bae34145639ddbf5ec..105ba4da618059b63a71a36747008e362a04233f 100644 (file)
@@ -125,72 +125,6 @@ static void caam_jr_dequeue(unsigned long devarg)
        clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK);
 }
 
-/**
- * caam_jr_register() - Alloc a ring for someone to use as needed. Returns
- * an ordinal of the rings allocated, else returns -ENODEV if no rings
- * are available.
- * @ctrldev: points to the controller level dev (parent) that
- *           owns rings available for use.
- * @dev:     points to where a pointer to the newly allocated queue's
- *           dev can be written to if successful.
- **/
-int caam_jr_register(struct device *ctrldev, struct device **rdev)
-{
-       struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
-       struct caam_drv_private_jr *jrpriv = NULL;
-       int ring;
-
-       /* Lock, if free ring - assign, unlock */
-       spin_lock(&ctrlpriv->jr_alloc_lock);
-       for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) {
-               jrpriv = dev_get_drvdata(ctrlpriv->jrdev[ring]);
-               if (jrpriv->assign == JOBR_UNASSIGNED) {
-                       jrpriv->assign = JOBR_ASSIGNED;
-                       *rdev = ctrlpriv->jrdev[ring];
-                       spin_unlock(&ctrlpriv->jr_alloc_lock);
-                       return ring;
-               }
-       }
-
-       /* If assigned, write dev where caller needs it */
-       spin_unlock(&ctrlpriv->jr_alloc_lock);
-       *rdev = NULL;
-
-       return -ENODEV;
-}
-EXPORT_SYMBOL(caam_jr_register);
-
-/**
- * caam_jr_deregister() - Deregister an API and release the queue.
- * Returns 0 if OK, -EBUSY if queue still contains pending entries
- * or unprocessed results at the time of the call
- * @dev     - points to the dev that identifies the queue to
- *            be released.
- **/
-int caam_jr_deregister(struct device *rdev)
-{
-       struct caam_drv_private_jr *jrpriv = dev_get_drvdata(rdev);
-       struct caam_drv_private *ctrlpriv;
-
-       /* Get the owning controller's private space */
-       ctrlpriv = dev_get_drvdata(jrpriv->parentdev);
-
-       /*
-        * Make sure ring empty before release
-        */
-       if (rd_reg32(&jrpriv->rregs->outring_used) ||
-           (rd_reg32(&jrpriv->rregs->inpring_avail) != JOBR_DEPTH))
-               return -EBUSY;
-
-       /* Release ring */
-       spin_lock(&ctrlpriv->jr_alloc_lock);
-       jrpriv->assign = JOBR_UNASSIGNED;
-       spin_unlock(&ctrlpriv->jr_alloc_lock);
-
-       return 0;
-}
-EXPORT_SYMBOL(caam_jr_deregister);
-
 /**
  * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK,
  * -EBUSY if the queue is full, -EIO if it cannot map the caller's
@@ -379,7 +313,6 @@ static int caam_jr_init(struct device *dev)
                  (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
                  (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
 
-       jrp->assign = JOBR_UNASSIGNED;
        return 0;
 }
 
index c23df395b6220b2b294610ea17254492b2e1dfd7..9d8741a59037f82ea162ef2a0b894bca49b5b040 100644 (file)
@@ -8,8 +8,6 @@
 #define JR_H
 
 /* Prototypes for backend-level services exposed to APIs */
-int caam_jr_register(struct device *ctrldev, struct device **rdev);
-int caam_jr_deregister(struct device *rdev);
 int caam_jr_enqueue(struct device *dev, u32 *desc,
                    void (*cbk)(struct device *dev, u32 *desc, u32 status,
                                void *areq),
index 87138d2adb5fe9144c4ebd9a46911363f10fbc1f..ea2e406610ebf9450008f2e2baf9ee65be0839a0 100644 (file)
@@ -95,9 +95,9 @@ int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len,
                          LDST_CLASS_2_CCB | FIFOST_TYPE_SPLIT_KEK);
 
 #ifdef DEBUG
-       print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1);
-       print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ",
+       print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
                       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
@@ -110,7 +110,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len,
                wait_for_completion_interruptible(&result.completion);
                ret = result.err;
 #ifdef DEBUG
-               print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ",
+               print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
                               DUMP_PREFIX_ADDRESS, 16, 4, key_out,
                               split_key_pad_len, 1);
 #endif
index c09142fc13e372171fe6093b45bdd6a3121f65f1..4455396918de84320380fcca2eca01d694971114 100644 (file)
@@ -341,6 +341,8 @@ struct caam_ctrl {
 #define MCFGR_DMA_RESET                0x10000000
 #define MCFGR_LONG_PTR         0x00010000 /* Use >32-bit desc addressing */
 #define SCFGR_RDBENABLE                0x00000400
+#define DECORR_RQD0ENABLE      0x00000001 /* Enable DECO0 for direct access */
+#define DECORR_DEN0            0x00010000 /* DECO0 available for access*/
 
 /* AXI read cache control */
 #define MCFGR_ARCACHE_SHIFT    12
@@ -703,9 +705,16 @@ struct caam_deco {
        struct deco_sg_table sctr_tbl[4];       /* DxSTR - Scatter Tables */
        u32 rsvd29[48];
        u32 descbuf[64];        /* DxDESB - Descriptor buffer */
-       u32 rsvd30[320];
+       u32 rscvd30[193];
+       u32 desc_dbg;           /* DxDDR - DECO Debug Register */
+       u32 rsvd31[126];
 };
 
+/* DECO DBG Register Valid Bit*/
+#define DECO_DBG_VALID         0x80000000
+#define DECO_JQCR_WHL          0x20000000
+#define DECO_JQCR_FOUR         0x10000000
+
 /*
  * Current top-level view of memory map is:
  *
@@ -733,6 +742,7 @@ struct caam_full {
        u64 rsvd[512];
        struct caam_assurance assure;
        struct caam_queue_if qi;
+       struct caam_deco deco;
 };
 
 #endif /* REGS_H */
index 35d483f8db66b2a3ecb204181ffd0d43b0aaaffe..cc00b52306ba69f45fcb90829719cbfb8946fdfd 100644 (file)
@@ -70,35 +70,52 @@ static int cbc_aes_nx_crypt(struct blkcipher_desc *desc,
 {
        struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
        struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       unsigned long irq_flags;
+       unsigned int processed = 0, to_process;
+       u32 max_sg_len;
        int rc;
 
-       if (nbytes > nx_ctx->ap->databytelen)
-               return -EINVAL;
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
+
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg),
+                          nx_ctx->ap->sglen);
 
        if (enc)
                NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
        else
                NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
 
-       rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes,
-                              csbcpb->cpb.aes_cbc.iv);
-       if (rc)
-               goto out;
-
-       if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
-               rc = -EINVAL;
-               goto out;
-       }
-
-       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
-                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
-       if (rc)
-               goto out;
-
-       atomic_inc(&(nx_ctx->stats->aes_ops));
-       atomic64_add(csbcpb->csb.processed_byte_count,
-                    &(nx_ctx->stats->aes_bytes));
+       do {
+               to_process = min_t(u64, nbytes - processed,
+                                  nx_ctx->ap->databytelen);
+               to_process = min_t(u64, to_process,
+                                  NX_PAGE_SIZE * (max_sg_len - 1));
+               to_process = to_process & ~(AES_BLOCK_SIZE - 1);
+
+               rc = nx_build_sg_lists(nx_ctx, desc, dst, src, to_process,
+                                      processed, csbcpb->cpb.aes_cbc.iv);
+               if (rc)
+                       goto out;
+
+               if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+
+               rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                                  desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+               if (rc)
+                       goto out;
+
+               memcpy(desc->info, csbcpb->cpb.aes_cbc.cv, AES_BLOCK_SIZE);
+               atomic_inc(&(nx_ctx->stats->aes_ops));
+               atomic64_add(csbcpb->csb.processed_byte_count,
+                            &(nx_ctx->stats->aes_bytes));
+
+               processed += to_process;
+       } while (processed < nbytes);
 out:
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return rc;
 }
 
index ef5eae6d1400382a8830bca980752b123e12bf52..5ecd4c2414aa85bbc9cbca1b4311a954dfcd3710 100644 (file)
@@ -179,13 +179,26 @@ static int generate_pat(u8                   *iv,
        struct nx_sg *nx_insg = nx_ctx->in_sg;
        struct nx_sg *nx_outsg = nx_ctx->out_sg;
        unsigned int iauth_len = 0;
-       struct vio_pfo_op *op = NULL;
        u8 tmp[16], *b1 = NULL, *b0 = NULL, *result = NULL;
        int rc;
 
        /* zero the ctr value */
        memset(iv + 15 - iv[0], 0, iv[0] + 1);
 
+       /* page 78 of nx_wb.pdf has,
+        * Note: RFC3610 allows the AAD data to be up to 2^64 -1 bytes
+        * in length. If a full message is used, the AES CCA implementation
+        * restricts the maximum AAD length to 2^32 -1 bytes.
+        * If partial messages are used, the implementation supports
+        * 2^64 -1 bytes maximum AAD length.
+        *
+        * However, in the cryptoapi's aead_request structure,
+        * assoclen is an unsigned int, thus it cannot hold a length
+        * value greater than 2^32 - 1.
+        * Thus the AAD is further constrained by this and is never
+        * greater than 2^32.
+        */
+
        if (!req->assoclen) {
                b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
        } else if (req->assoclen <= 14) {
@@ -195,7 +208,46 @@ static int generate_pat(u8                   *iv,
                b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
                b1 = nx_ctx->priv.ccm.iauth_tag;
                iauth_len = req->assoclen;
+       } else if (req->assoclen <= 65280) {
+               /* if associated data is less than (2^16 - 2^8), we construct
+                * B1 differently and feed in the associated data to a CCA
+                * operation */
+               b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
+               b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
+               iauth_len = 14;
+       } else {
+               b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
+               b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
+               iauth_len = 10;
+       }
+
+       /* generate B0 */
+       rc = generate_b0(iv, req->assoclen, authsize, nbytes, b0);
+       if (rc)
+               return rc;
+
+       /* generate B1:
+        * add control info for associated data
+        * RFC 3610 and NIST Special Publication 800-38C
+        */
+       if (b1) {
+               memset(b1, 0, 16);
+               if (req->assoclen <= 65280) {
+                       *(u16 *)b1 = (u16)req->assoclen;
+                       scatterwalk_map_and_copy(b1 + 2, req->assoc, 0,
+                                        iauth_len, SCATTERWALK_FROM_SG);
+               } else {
+                       *(u16 *)b1 = (u16)(0xfffe);
+                       *(u32 *)&b1[2] = (u32)req->assoclen;
+                       scatterwalk_map_and_copy(b1 + 6, req->assoc, 0,
+                                        iauth_len, SCATTERWALK_FROM_SG);
+               }
+       }
 
+       /* now copy any remaining AAD to scatterlist and call nx... */
+       if (!req->assoclen) {
+               return rc;
+       } else if (req->assoclen <= 14) {
                nx_insg = nx_build_sg_list(nx_insg, b1, 16, nx_ctx->ap->sglen);
                nx_outsg = nx_build_sg_list(nx_outsg, tmp, 16,
                                            nx_ctx->ap->sglen);
@@ -210,56 +262,74 @@ static int generate_pat(u8                   *iv,
                NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_ENDE_ENCRYPT;
                NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_INTERMEDIATE;
 
-               op = &nx_ctx->op;
                result = nx_ctx->csbcpb->cpb.aes_ccm.out_pat_or_mac;
-       } else if (req->assoclen <= 65280) {
-               /* if associated data is less than (2^16 - 2^8), we construct
-                * B1 differently and feed in the associated data to a CCA
-                * operation */
-               b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
-               b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
-               iauth_len = 14;
 
-               /* remaining assoc data must have scatterlist built for it */
-               nx_insg = nx_walk_and_build(nx_insg, nx_ctx->ap->sglen,
-                                           req->assoc, iauth_len,
-                                           req->assoclen - iauth_len);
-               nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) *
-                                               sizeof(struct nx_sg);
+               rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                                  req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+               if (rc)
+                       return rc;
+
+               atomic_inc(&(nx_ctx->stats->aes_ops));
+               atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
 
-               op = &nx_ctx->op_aead;
-               result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
        } else {
-               /* if associated data is less than (2^32), we construct B1
-                * differently yet again and feed in the associated data to a
-                * CCA operation */
-               pr_err("associated data len is %u bytes (returning -EINVAL)\n",
-                      req->assoclen);
-               rc = -EINVAL;
-       }
+               u32 max_sg_len;
+               unsigned int processed = 0, to_process;
+
+               /* page_limit: number of sg entries that fit on one page */
+               max_sg_len = min_t(u32,
+                                  nx_driver.of.max_sg_len/sizeof(struct nx_sg),
+                                  nx_ctx->ap->sglen);
+
+               processed += iauth_len;
+
+               do {
+                       to_process = min_t(u32, req->assoclen - processed,
+                                          nx_ctx->ap->databytelen);
+                       to_process = min_t(u64, to_process,
+                                          NX_PAGE_SIZE * (max_sg_len - 1));
+
+                       if ((to_process + processed) < req->assoclen) {
+                               NX_CPB_FDM(nx_ctx->csbcpb_aead) |=
+                                       NX_FDM_INTERMEDIATE;
+                       } else {
+                               NX_CPB_FDM(nx_ctx->csbcpb_aead) &=
+                                       ~NX_FDM_INTERMEDIATE;
+                       }
+
+                       nx_insg = nx_walk_and_build(nx_ctx->in_sg,
+                                                   nx_ctx->ap->sglen,
+                                                   req->assoc, processed,
+                                                   to_process);
+
+                       nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) *
+                                               sizeof(struct nx_sg);
 
-       rc = generate_b0(iv, req->assoclen, authsize, nbytes, b0);
-       if (rc)
-               goto done;
+                       result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
 
-       if (b1) {
-               memset(b1, 0, 16);
-               *(u16 *)b1 = (u16)req->assoclen;
+                       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op_aead,
+                                  req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+                       if (rc)
+                               return rc;
 
-               scatterwalk_map_and_copy(b1 + 2, req->assoc, 0,
-                                        iauth_len, SCATTERWALK_FROM_SG);
+                       memcpy(nx_ctx->csbcpb_aead->cpb.aes_cca.b0,
+                               nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0,
+                               AES_BLOCK_SIZE);
 
-               rc = nx_hcall_sync(nx_ctx, op,
-                                  req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
-               if (rc)
-                       goto done;
+                       NX_CPB_FDM(nx_ctx->csbcpb_aead) |= NX_FDM_CONTINUATION;
 
-               atomic_inc(&(nx_ctx->stats->aes_ops));
-               atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
+                       atomic_inc(&(nx_ctx->stats->aes_ops));
+                       atomic64_add(req->assoclen,
+                                       &(nx_ctx->stats->aes_bytes));
 
-               memcpy(out, result, AES_BLOCK_SIZE);
+                       processed += to_process;
+               } while (processed < req->assoclen);
+
+               result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
        }
-done:
+
+       memcpy(out, result, AES_BLOCK_SIZE);
+
        return rc;
 }
 
@@ -271,10 +341,12 @@ static int ccm_nx_decrypt(struct aead_request   *req,
        unsigned int nbytes = req->cryptlen;
        unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
        struct nx_ccm_priv *priv = &nx_ctx->priv.ccm;
+       unsigned long irq_flags;
+       unsigned int processed = 0, to_process;
+       u32 max_sg_len;
        int rc = -1;
 
-       if (nbytes > nx_ctx->ap->databytelen)
-               return -EINVAL;
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
 
        nbytes -= authsize;
 
@@ -288,26 +360,61 @@ static int ccm_nx_decrypt(struct aead_request   *req,
        if (rc)
                goto out;
 
-       rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, nbytes,
-                              csbcpb->cpb.aes_ccm.iv_or_ctr);
-       if (rc)
-               goto out;
+       /* page_limit: number of sg entries that fit on one page */
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg),
+                          nx_ctx->ap->sglen);
 
-       NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
-       NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_INTERMEDIATE;
+       do {
+
+               /* to_process: the AES_BLOCK_SIZE data chunk to process in this
+                * update. This value is bound by sg list limits.
+                */
+               to_process = min_t(u64, nbytes - processed,
+                                  nx_ctx->ap->databytelen);
+               to_process = min_t(u64, to_process,
+                                  NX_PAGE_SIZE * (max_sg_len - 1));
+
+               if ((to_process + processed) < nbytes)
+                       NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+               else
+                       NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+               NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+
+               rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src,
+                                       to_process, processed,
+                                       csbcpb->cpb.aes_ccm.iv_or_ctr);
+               if (rc)
+                       goto out;
 
-       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+               rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
                           req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
-       if (rc)
-               goto out;
+               if (rc)
+                       goto out;
 
-       atomic_inc(&(nx_ctx->stats->aes_ops));
-       atomic64_add(csbcpb->csb.processed_byte_count,
-                    &(nx_ctx->stats->aes_bytes));
+               /* for partial completion, copy following for next
+                * entry into loop...
+                */
+               memcpy(desc->info, csbcpb->cpb.aes_ccm.out_ctr, AES_BLOCK_SIZE);
+               memcpy(csbcpb->cpb.aes_ccm.in_pat_or_b0,
+                       csbcpb->cpb.aes_ccm.out_pat_or_mac, AES_BLOCK_SIZE);
+               memcpy(csbcpb->cpb.aes_ccm.in_s0,
+                       csbcpb->cpb.aes_ccm.out_s0, AES_BLOCK_SIZE);
+
+               NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+
+               /* update stats */
+               atomic_inc(&(nx_ctx->stats->aes_ops));
+               atomic64_add(csbcpb->csb.processed_byte_count,
+                            &(nx_ctx->stats->aes_bytes));
+
+               processed += to_process;
+       } while (processed < nbytes);
 
        rc = memcmp(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
                    authsize) ? -EBADMSG : 0;
 out:
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return rc;
 }
 
@@ -318,38 +425,76 @@ static int ccm_nx_encrypt(struct aead_request   *req,
        struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
        unsigned int nbytes = req->cryptlen;
        unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
+       unsigned long irq_flags;
+       unsigned int processed = 0, to_process;
+       u32 max_sg_len;
        int rc = -1;
 
-       if (nbytes > nx_ctx->ap->databytelen)
-               return -EINVAL;
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
 
        rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes,
                          csbcpb->cpb.aes_ccm.in_pat_or_b0);
        if (rc)
                goto out;
 
-       rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, nbytes,
-                              csbcpb->cpb.aes_ccm.iv_or_ctr);
-       if (rc)
-               goto out;
+       /* page_limit: number of sg entries that fit on one page */
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg),
+                          nx_ctx->ap->sglen);
+
+       do {
+               /* to process: the AES_BLOCK_SIZE data chunk to process in this
+                * update. This value is bound by sg list limits.
+                */
+               to_process = min_t(u64, nbytes - processed,
+                                  nx_ctx->ap->databytelen);
+               to_process = min_t(u64, to_process,
+                                  NX_PAGE_SIZE * (max_sg_len - 1));
+
+               if ((to_process + processed) < nbytes)
+                       NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+               else
+                       NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+               NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+
+               rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src,
+                                       to_process, processed,
+                                      csbcpb->cpb.aes_ccm.iv_or_ctr);
+               if (rc)
+                       goto out;
 
-       NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
-       NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+               rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                                  req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+               if (rc)
+                       goto out;
 
-       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
-                          req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
-       if (rc)
-               goto out;
+               /* for partial completion, copy following for next
+                * entry into loop...
+                */
+               memcpy(desc->info, csbcpb->cpb.aes_ccm.out_ctr, AES_BLOCK_SIZE);
+               memcpy(csbcpb->cpb.aes_ccm.in_pat_or_b0,
+                       csbcpb->cpb.aes_ccm.out_pat_or_mac, AES_BLOCK_SIZE);
+               memcpy(csbcpb->cpb.aes_ccm.in_s0,
+                       csbcpb->cpb.aes_ccm.out_s0, AES_BLOCK_SIZE);
 
-       atomic_inc(&(nx_ctx->stats->aes_ops));
-       atomic64_add(csbcpb->csb.processed_byte_count,
-                    &(nx_ctx->stats->aes_bytes));
+               NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+
+               /* update stats */
+               atomic_inc(&(nx_ctx->stats->aes_ops));
+               atomic64_add(csbcpb->csb.processed_byte_count,
+                            &(nx_ctx->stats->aes_bytes));
+
+               processed += to_process;
+
+       } while (processed < nbytes);
 
        /* copy out the auth tag */
        scatterwalk_map_and_copy(csbcpb->cpb.aes_ccm.out_pat_or_mac,
                                 req->dst, nbytes, authsize,
                                 SCATTERWALK_TO_SG);
+
 out:
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return rc;
 }
 
index b6286f14680ba82fcb7a32136dddea9b2a24ce29..a37d009dc75c76efef57cf7f2e4437c113fcae7e 100644 (file)
@@ -88,30 +88,48 @@ static int ctr_aes_nx_crypt(struct blkcipher_desc *desc,
 {
        struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
        struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       unsigned long irq_flags;
+       unsigned int processed = 0, to_process;
+       u32 max_sg_len;
        int rc;
 
-       if (nbytes > nx_ctx->ap->databytelen)
-               return -EINVAL;
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
 
-       rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes,
-                              csbcpb->cpb.aes_ctr.iv);
-       if (rc)
-               goto out;
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg),
+                          nx_ctx->ap->sglen);
 
-       if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
-               rc = -EINVAL;
-               goto out;
-       }
+       do {
+               to_process = min_t(u64, nbytes - processed,
+                                  nx_ctx->ap->databytelen);
+               to_process = min_t(u64, to_process,
+                                  NX_PAGE_SIZE * (max_sg_len - 1));
+               to_process = to_process & ~(AES_BLOCK_SIZE - 1);
+
+               rc = nx_build_sg_lists(nx_ctx, desc, dst, src, to_process,
+                                      processed, csbcpb->cpb.aes_ctr.iv);
+               if (rc)
+                       goto out;
+
+               if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+
+               rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                                  desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+               if (rc)
+                       goto out;
+
+               memcpy(desc->info, csbcpb->cpb.aes_cbc.cv, AES_BLOCK_SIZE);
 
-       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
-                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
-       if (rc)
-               goto out;
+               atomic_inc(&(nx_ctx->stats->aes_ops));
+               atomic64_add(csbcpb->csb.processed_byte_count,
+                            &(nx_ctx->stats->aes_bytes));
 
-       atomic_inc(&(nx_ctx->stats->aes_ops));
-       atomic64_add(csbcpb->csb.processed_byte_count,
-                    &(nx_ctx->stats->aes_bytes));
+               processed += to_process;
+       } while (processed < nbytes);
 out:
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return rc;
 }
 
index 7bbc9a81da219e5c27e021c9ef6c880d194c90d3..85a8d23cf29d72b14180c6f7e7777786010c2094 100644 (file)
@@ -70,34 +70,52 @@ static int ecb_aes_nx_crypt(struct blkcipher_desc *desc,
 {
        struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
        struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       unsigned long irq_flags;
+       unsigned int processed = 0, to_process;
+       u32 max_sg_len;
        int rc;
 
-       if (nbytes > nx_ctx->ap->databytelen)
-               return -EINVAL;
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
+
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg),
+                          nx_ctx->ap->sglen);
 
        if (enc)
                NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
        else
                NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
 
-       rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes, NULL);
-       if (rc)
-               goto out;
+       do {
+               to_process = min_t(u64, nbytes - processed,
+                                  nx_ctx->ap->databytelen);
+               to_process = min_t(u64, to_process,
+                                  NX_PAGE_SIZE * (max_sg_len - 1));
+               to_process = to_process & ~(AES_BLOCK_SIZE - 1);
 
-       if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
-               rc = -EINVAL;
-               goto out;
-       }
+               rc = nx_build_sg_lists(nx_ctx, desc, dst, src, to_process,
+                               processed, NULL);
+               if (rc)
+                       goto out;
+
+               if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+
+               rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                                  desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+               if (rc)
+                       goto out;
+
+               atomic_inc(&(nx_ctx->stats->aes_ops));
+               atomic64_add(csbcpb->csb.processed_byte_count,
+                            &(nx_ctx->stats->aes_bytes));
 
-       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
-                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
-       if (rc)
-               goto out;
+               processed += to_process;
+       } while (processed < nbytes);
 
-       atomic_inc(&(nx_ctx->stats->aes_ops));
-       atomic64_add(csbcpb->csb.processed_byte_count,
-                    &(nx_ctx->stats->aes_bytes));
 out:
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return rc;
 }
 
index 6cca6c392b00f34fa65ad4663b1725bd7b3842fe..025d9a8d5b1908126804c8468d30ec6902cb4c59 100644 (file)
@@ -125,38 +125,187 @@ static int nx_gca(struct nx_crypto_ctx  *nx_ctx,
                  struct aead_request   *req,
                  u8                    *out)
 {
+       int rc;
        struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
-       int rc = -EINVAL;
        struct scatter_walk walk;
        struct nx_sg *nx_sg = nx_ctx->in_sg;
+       unsigned int nbytes = req->assoclen;
+       unsigned int processed = 0, to_process;
+       u32 max_sg_len;
 
-       if (req->assoclen > nx_ctx->ap->databytelen)
-               goto out;
-
-       if (req->assoclen <= AES_BLOCK_SIZE) {
+       if (nbytes <= AES_BLOCK_SIZE) {
                scatterwalk_start(&walk, req->assoc);
-               scatterwalk_copychunks(out, &walk, req->assoclen,
-                                      SCATTERWALK_FROM_SG);
+               scatterwalk_copychunks(out, &walk, nbytes, SCATTERWALK_FROM_SG);
                scatterwalk_done(&walk, SCATTERWALK_FROM_SG, 0);
-
-               rc = 0;
-               goto out;
+               return 0;
        }
 
-       nx_sg = nx_walk_and_build(nx_sg, nx_ctx->ap->sglen, req->assoc, 0,
-                                 req->assoclen);
-       nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_sg) * sizeof(struct nx_sg);
+       NX_CPB_FDM(csbcpb_aead) &= ~NX_FDM_CONTINUATION;
+
+       /* page_limit: number of sg entries that fit on one page */
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg),
+                          nx_ctx->ap->sglen);
+
+       do {
+               /*
+                * to_process: the data chunk to process in this update.
+                * This value is bound by sg list limits.
+                */
+               to_process = min_t(u64, nbytes - processed,
+                                  nx_ctx->ap->databytelen);
+               to_process = min_t(u64, to_process,
+                                  NX_PAGE_SIZE * (max_sg_len - 1));
+
+               if ((to_process + processed) < nbytes)
+                       NX_CPB_FDM(csbcpb_aead) |= NX_FDM_INTERMEDIATE;
+               else
+                       NX_CPB_FDM(csbcpb_aead) &= ~NX_FDM_INTERMEDIATE;
+
+               nx_sg = nx_walk_and_build(nx_ctx->in_sg, nx_ctx->ap->sglen,
+                                         req->assoc, processed, to_process);
+               nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_sg)
+                                       * sizeof(struct nx_sg);
+
+               rc = nx_hcall_sync(nx_ctx, &nx_ctx->op_aead,
+                               req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+               if (rc)
+                       return rc;
+
+               memcpy(csbcpb_aead->cpb.aes_gca.in_pat,
+                               csbcpb_aead->cpb.aes_gca.out_pat,
+                               AES_BLOCK_SIZE);
+               NX_CPB_FDM(csbcpb_aead) |= NX_FDM_CONTINUATION;
+
+               atomic_inc(&(nx_ctx->stats->aes_ops));
+               atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
+
+               processed += to_process;
+       } while (processed < nbytes);
+
+       memcpy(out, csbcpb_aead->cpb.aes_gca.out_pat, AES_BLOCK_SIZE);
+
+       return rc;
+}
+
+static int gmac(struct aead_request *req, struct blkcipher_desc *desc)
+{
+       int rc;
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       struct nx_sg *nx_sg;
+       unsigned int nbytes = req->assoclen;
+       unsigned int processed = 0, to_process;
+       u32 max_sg_len;
+
+       /* Set GMAC mode */
+       csbcpb->cpb.hdr.mode = NX_MODE_AES_GMAC;
+
+       NX_CPB_FDM(csbcpb) &= ~NX_FDM_CONTINUATION;
+
+       /* page_limit: number of sg entries that fit on one page */
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg),
+                          nx_ctx->ap->sglen);
+
+       /* Copy IV */
+       memcpy(csbcpb->cpb.aes_gcm.iv_or_cnt, desc->info, AES_BLOCK_SIZE);
+
+       do {
+               /*
+                * to_process: the data chunk to process in this update.
+                * This value is bound by sg list limits.
+                */
+               to_process = min_t(u64, nbytes - processed,
+                                  nx_ctx->ap->databytelen);
+               to_process = min_t(u64, to_process,
+                                  NX_PAGE_SIZE * (max_sg_len - 1));
+
+               if ((to_process + processed) < nbytes)
+                       NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+               else
+                       NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+               nx_sg = nx_walk_and_build(nx_ctx->in_sg, nx_ctx->ap->sglen,
+                                         req->assoc, processed, to_process);
+               nx_ctx->op.inlen = (nx_ctx->in_sg - nx_sg)
+                                       * sizeof(struct nx_sg);
+
+               csbcpb->cpb.aes_gcm.bit_length_data = 0;
+               csbcpb->cpb.aes_gcm.bit_length_aad = 8 * nbytes;
+
+               rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                               req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+               if (rc)
+                       goto out;
+
+               memcpy(csbcpb->cpb.aes_gcm.in_pat_or_aad,
+                       csbcpb->cpb.aes_gcm.out_pat_or_mac, AES_BLOCK_SIZE);
+               memcpy(csbcpb->cpb.aes_gcm.in_s0,
+                       csbcpb->cpb.aes_gcm.out_s0, AES_BLOCK_SIZE);
+
+               NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+
+               atomic_inc(&(nx_ctx->stats->aes_ops));
+               atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
+
+               processed += to_process;
+       } while (processed < nbytes);
+
+out:
+       /* Restore GCM mode */
+       csbcpb->cpb.hdr.mode = NX_MODE_AES_GCM;
+       return rc;
+}
+
+static int gcm_empty(struct aead_request *req, struct blkcipher_desc *desc,
+                    int enc)
+{
+       int rc;
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       char out[AES_BLOCK_SIZE];
+       struct nx_sg *in_sg, *out_sg;
+
+       /* For scenarios where the input message is zero length, AES CTR mode
+        * may be used. Set the source data to be a single block (16B) of all
+        * zeros, and set the input IV value to be the same as the GMAC IV
+        * value. - nx_wb 4.8.1.3 */
+
+       /* Change to ECB mode */
+       csbcpb->cpb.hdr.mode = NX_MODE_AES_ECB;
+       memcpy(csbcpb->cpb.aes_ecb.key, csbcpb->cpb.aes_gcm.key,
+                       sizeof(csbcpb->cpb.aes_ecb.key));
+       if (enc)
+               NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+       else
+               NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+
+       /* Encrypt the counter/IV */
+       in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *) desc->info,
+                                AES_BLOCK_SIZE, nx_ctx->ap->sglen);
+       out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *) out, sizeof(out),
+                                 nx_ctx->ap->sglen);
+       nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
 
-       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op_aead,
-                          req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
        if (rc)
                goto out;
-
        atomic_inc(&(nx_ctx->stats->aes_ops));
-       atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
 
-       memcpy(out, csbcpb_aead->cpb.aes_gca.out_pat, AES_BLOCK_SIZE);
+       /* Copy out the auth tag */
+       memcpy(csbcpb->cpb.aes_gcm.out_pat_or_mac, out,
+                       crypto_aead_authsize(crypto_aead_reqtfm(req)));
 out:
+       /* Restore XCBC mode */
+       csbcpb->cpb.hdr.mode = NX_MODE_AES_GCM;
+
+       /*
+        * ECB key uses the same region that GCM AAD and counter, so it's safe
+        * to just fill it with zeroes.
+        */
+       memset(csbcpb->cpb.aes_ecb.key, 0, sizeof(csbcpb->cpb.aes_ecb.key));
+
        return rc;
 }
 
@@ -166,88 +315,104 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc)
        struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
        struct blkcipher_desc desc;
        unsigned int nbytes = req->cryptlen;
+       unsigned int processed = 0, to_process;
+       unsigned long irq_flags;
+       u32 max_sg_len;
        int rc = -EINVAL;
 
-       if (nbytes > nx_ctx->ap->databytelen)
-               goto out;
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
 
        desc.info = nx_ctx->priv.gcm.iv;
        /* initialize the counter */
        *(u32 *)(desc.info + NX_GCM_CTR_OFFSET) = 1;
 
-       /* For scenarios where the input message is zero length, AES CTR mode
-        * may be used. Set the source data to be a single block (16B) of all
-        * zeros, and set the input IV value to be the same as the GMAC IV
-        * value. - nx_wb 4.8.1.3 */
        if (nbytes == 0) {
-               char src[AES_BLOCK_SIZE] = {};
-               struct scatterlist sg;
-
-               desc.tfm = crypto_alloc_blkcipher("ctr(aes)", 0, 0);
-               if (IS_ERR(desc.tfm)) {
-                       rc = -ENOMEM;
+               if (req->assoclen == 0)
+                       rc = gcm_empty(req, &desc, enc);
+               else
+                       rc = gmac(req, &desc);
+               if (rc)
                        goto out;
-               }
-
-               crypto_blkcipher_setkey(desc.tfm, csbcpb->cpb.aes_gcm.key,
-                       NX_CPB_KEY_SIZE(csbcpb) == NX_KS_AES_128 ? 16 :
-                       NX_CPB_KEY_SIZE(csbcpb) == NX_KS_AES_192 ? 24 : 32);
-
-               sg_init_one(&sg, src, AES_BLOCK_SIZE);
-               if (enc)
-                       crypto_blkcipher_encrypt_iv(&desc, req->dst, &sg,
-                                                   AES_BLOCK_SIZE);
                else
-                       crypto_blkcipher_decrypt_iv(&desc, req->dst, &sg,
-                                                   AES_BLOCK_SIZE);
-               crypto_free_blkcipher(desc.tfm);
-
-               rc = 0;
-               goto out;
+                       goto mac;
        }
 
-       desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
-
+       /* Process associated data */
        csbcpb->cpb.aes_gcm.bit_length_aad = req->assoclen * 8;
-
        if (req->assoclen) {
                rc = nx_gca(nx_ctx, req, csbcpb->cpb.aes_gcm.in_pat_or_aad);
                if (rc)
                        goto out;
        }
 
-       if (enc)
+       /* Set flags for encryption */
+       NX_CPB_FDM(csbcpb) &= ~NX_FDM_CONTINUATION;
+       if (enc) {
                NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
-       else
+       } else {
+               NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
                nbytes -= crypto_aead_authsize(crypto_aead_reqtfm(req));
+       }
 
-       csbcpb->cpb.aes_gcm.bit_length_data = nbytes * 8;
+       /* page_limit: number of sg entries that fit on one page */
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg),
+                          nx_ctx->ap->sglen);
+
+       do {
+               /*
+                * to_process: the data chunk to process in this update.
+                * This value is bound by sg list limits.
+                */
+               to_process = min_t(u64, nbytes - processed,
+                                  nx_ctx->ap->databytelen);
+               to_process = min_t(u64, to_process,
+                                  NX_PAGE_SIZE * (max_sg_len - 1));
+
+               if ((to_process + processed) < nbytes)
+                       NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+               else
+                       NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
 
-       rc = nx_build_sg_lists(nx_ctx, &desc, req->dst, req->src, nbytes,
-                              csbcpb->cpb.aes_gcm.iv_or_cnt);
-       if (rc)
-               goto out;
+               csbcpb->cpb.aes_gcm.bit_length_data = nbytes * 8;
+               desc.tfm = (struct crypto_blkcipher *) req->base.tfm;
+               rc = nx_build_sg_lists(nx_ctx, &desc, req->dst,
+                                      req->src, to_process, processed,
+                                      csbcpb->cpb.aes_gcm.iv_or_cnt);
+               if (rc)
+                       goto out;
 
-       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
-                          req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
-       if (rc)
-               goto out;
+               rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                                  req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+               if (rc)
+                       goto out;
 
-       atomic_inc(&(nx_ctx->stats->aes_ops));
-       atomic64_add(csbcpb->csb.processed_byte_count,
-                    &(nx_ctx->stats->aes_bytes));
+               memcpy(desc.info, csbcpb->cpb.aes_gcm.out_cnt, AES_BLOCK_SIZE);
+               memcpy(csbcpb->cpb.aes_gcm.in_pat_or_aad,
+                       csbcpb->cpb.aes_gcm.out_pat_or_mac, AES_BLOCK_SIZE);
+               memcpy(csbcpb->cpb.aes_gcm.in_s0,
+                       csbcpb->cpb.aes_gcm.out_s0, AES_BLOCK_SIZE);
+
+               NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+
+               atomic_inc(&(nx_ctx->stats->aes_ops));
+               atomic64_add(csbcpb->csb.processed_byte_count,
+                            &(nx_ctx->stats->aes_bytes));
+
+               processed += to_process;
+       } while (processed < nbytes);
 
+mac:
        if (enc) {
                /* copy out the auth tag */
                scatterwalk_map_and_copy(csbcpb->cpb.aes_gcm.out_pat_or_mac,
                                 req->dst, nbytes,
                                 crypto_aead_authsize(crypto_aead_reqtfm(req)),
                                 SCATTERWALK_TO_SG);
-       } else if (req->assoclen) {
+       } else {
                u8 *itag = nx_ctx->priv.gcm.iauth_tag;
                u8 *otag = csbcpb->cpb.aes_gcm.out_pat_or_mac;
 
-               scatterwalk_map_and_copy(itag, req->dst, nbytes,
+               scatterwalk_map_and_copy(itag, req->src, nbytes,
                                 crypto_aead_authsize(crypto_aead_reqtfm(req)),
                                 SCATTERWALK_FROM_SG);
                rc = memcmp(itag, otag,
@@ -255,6 +420,7 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc)
                     -EBADMSG : 0;
        }
 out:
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return rc;
 }
 
index 93923e4628c05b8af34bf19e90eb3cb692a4a0a0..03c4bf57d066b230d8750875eb8bdc33429cd357 100644 (file)
@@ -56,6 +56,77 @@ static int nx_xcbc_set_key(struct crypto_shash *desc,
        return 0;
 }
 
+/*
+ * Based on RFC 3566, for a zero-length message:
+ *
+ * n = 1
+ * K1 = E(K, 0x01010101010101010101010101010101)
+ * K3 = E(K, 0x03030303030303030303030303030303)
+ * E[0] = 0x00000000000000000000000000000000
+ * M[1] = 0x80000000000000000000000000000000 (0 length message with padding)
+ * E[1] = (K1, M[1] ^ E[0] ^ K3)
+ * Tag = M[1]
+ */
+static int nx_xcbc_empty(struct shash_desc *desc, u8 *out)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       struct nx_sg *in_sg, *out_sg;
+       u8 keys[2][AES_BLOCK_SIZE];
+       u8 key[32];
+       int rc = 0;
+
+       /* Change to ECB mode */
+       csbcpb->cpb.hdr.mode = NX_MODE_AES_ECB;
+       memcpy(key, csbcpb->cpb.aes_xcbc.key, AES_BLOCK_SIZE);
+       memcpy(csbcpb->cpb.aes_ecb.key, key, AES_BLOCK_SIZE);
+       NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+
+       /* K1 and K3 base patterns */
+       memset(keys[0], 0x01, sizeof(keys[0]));
+       memset(keys[1], 0x03, sizeof(keys[1]));
+
+       /* Generate K1 and K3 encrypting the patterns */
+       in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *) keys, sizeof(keys),
+                                nx_ctx->ap->sglen);
+       out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *) keys, sizeof(keys),
+                                 nx_ctx->ap->sglen);
+       nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+       atomic_inc(&(nx_ctx->stats->aes_ops));
+
+       /* XOr K3 with the padding for a 0 length message */
+       keys[1][0] ^= 0x80;
+
+       /* Encrypt the final result */
+       memcpy(csbcpb->cpb.aes_ecb.key, keys[0], AES_BLOCK_SIZE);
+       in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *) keys[1], sizeof(keys[1]),
+                                nx_ctx->ap->sglen);
+       out_sg = nx_build_sg_list(nx_ctx->out_sg, out, AES_BLOCK_SIZE,
+                                 nx_ctx->ap->sglen);
+       nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+       atomic_inc(&(nx_ctx->stats->aes_ops));
+
+out:
+       /* Restore XCBC mode */
+       csbcpb->cpb.hdr.mode = NX_MODE_AES_XCBC_MAC;
+       memcpy(csbcpb->cpb.aes_xcbc.key, key, AES_BLOCK_SIZE);
+       NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+
+       return rc;
+}
+
 static int nx_xcbc_init(struct shash_desc *desc)
 {
        struct xcbc_state *sctx = shash_desc_ctx(desc);
@@ -88,76 +159,99 @@ static int nx_xcbc_update(struct shash_desc *desc,
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
        struct nx_sg *in_sg;
-       u32 to_process, leftover;
+       u32 to_process, leftover, total;
+       u32 max_sg_len;
+       unsigned long irq_flags;
        int rc = 0;
 
-       if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
-               /* we've hit the nx chip previously and we're updating again,
-                * so copy over the partial digest */
-               memcpy(csbcpb->cpb.aes_xcbc.cv,
-                      csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
-       }
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
+
+
+       total = sctx->count + len;
 
        /* 2 cases for total data len:
         *  1: <= AES_BLOCK_SIZE: copy into state, return 0
         *  2: > AES_BLOCK_SIZE: process X blocks, copy in leftover
         */
-       if (len + sctx->count <= AES_BLOCK_SIZE) {
+       if (total <= AES_BLOCK_SIZE) {
                memcpy(sctx->buffer + sctx->count, data, len);
                sctx->count += len;
                goto out;
        }
 
-       /* to_process: the AES_BLOCK_SIZE data chunk to process in this
-        * update */
-       to_process = (sctx->count + len) & ~(AES_BLOCK_SIZE - 1);
-       leftover = (sctx->count + len) & (AES_BLOCK_SIZE - 1);
-
-       /* the hardware will not accept a 0 byte operation for this algorithm
-        * and the operation MUST be finalized to be correct. So if we happen
-        * to get an update that falls on a block sized boundary, we must
-        * save off the last block to finalize with later. */
-       if (!leftover) {
-               to_process -= AES_BLOCK_SIZE;
-               leftover = AES_BLOCK_SIZE;
-       }
-
-       if (sctx->count) {
-               in_sg = nx_build_sg_list(nx_ctx->in_sg, sctx->buffer,
-                                        sctx->count, nx_ctx->ap->sglen);
-               in_sg = nx_build_sg_list(in_sg, (u8 *)data,
-                                        to_process - sctx->count,
-                                        nx_ctx->ap->sglen);
+       in_sg = nx_ctx->in_sg;
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg),
+                               nx_ctx->ap->sglen);
+
+       do {
+
+               /* to_process: the AES_BLOCK_SIZE data chunk to process in this
+                * update */
+               to_process = min_t(u64, total, nx_ctx->ap->databytelen);
+               to_process = min_t(u64, to_process,
+                                       NX_PAGE_SIZE * (max_sg_len - 1));
+               to_process = to_process & ~(AES_BLOCK_SIZE - 1);
+               leftover = total - to_process;
+
+               /* the hardware will not accept a 0 byte operation for this
+                * algorithm and the operation MUST be finalized to be correct.
+                * So if we happen to get an update that falls on a block sized
+                * boundary, we must save off the last block to finalize with
+                * later. */
+               if (!leftover) {
+                       to_process -= AES_BLOCK_SIZE;
+                       leftover = AES_BLOCK_SIZE;
+               }
+
+               if (sctx->count) {
+                       in_sg = nx_build_sg_list(nx_ctx->in_sg,
+                                               (u8 *) sctx->buffer,
+                                               sctx->count,
+                                               max_sg_len);
+               }
+               in_sg = nx_build_sg_list(in_sg,
+                                       (u8 *) data,
+                                       to_process - sctx->count,
+                                       max_sg_len);
                nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
                                        sizeof(struct nx_sg);
-       } else {
-               in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data, to_process,
-                                        nx_ctx->ap->sglen);
-               nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
-                                       sizeof(struct nx_sg);
-       }
 
-       NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+               /* we've hit the nx chip previously and we're updating again,
+                * so copy over the partial digest */
+               if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+                       memcpy(csbcpb->cpb.aes_xcbc.cv,
+                               csbcpb->cpb.aes_xcbc.out_cv_mac,
+                               AES_BLOCK_SIZE);
+               }
+
+               NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+               if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+
+               rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+               if (rc)
+                       goto out;
 
-       if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
-               rc = -EINVAL;
-               goto out;
-       }
+               atomic_inc(&(nx_ctx->stats->aes_ops));
 
-       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
-                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
-       if (rc)
-               goto out;
+               /* everything after the first update is continuation */
+               NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
 
-       atomic_inc(&(nx_ctx->stats->aes_ops));
+               total -= to_process;
+               data += to_process - sctx->count;
+               sctx->count = 0;
+               in_sg = nx_ctx->in_sg;
+       } while (leftover > AES_BLOCK_SIZE);
 
        /* copy the leftover back into the state struct */
-       memcpy(sctx->buffer, data + len - leftover, leftover);
+       memcpy(sctx->buffer, data, leftover);
        sctx->count = leftover;
 
-       /* everything after the first update is continuation */
-       NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
 out:
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return rc;
 }
 
@@ -167,21 +261,23 @@ static int nx_xcbc_final(struct shash_desc *desc, u8 *out)
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
        struct nx_sg *in_sg, *out_sg;
+       unsigned long irq_flags;
        int rc = 0;
 
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
+
        if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
                /* we've hit the nx chip previously, now we're finalizing,
                 * so copy over the partial digest */
                memcpy(csbcpb->cpb.aes_xcbc.cv,
                       csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
        } else if (sctx->count == 0) {
-               /* we've never seen an update, so this is a 0 byte op. The
-                * hardware cannot handle a 0 byte op, so just copy out the
-                * known 0 byte result. This is cheaper than allocating a
-                * software context to do a 0 byte op */
-               u8 data[] = { 0x75, 0xf0, 0x25, 0x1d, 0x52, 0x8a, 0xc0, 0x1c,
-                             0x45, 0x73, 0xdf, 0xd5, 0x84, 0xd7, 0x9f, 0x29 };
-               memcpy(out, data, sizeof(data));
+               /*
+                * we've never seen an update, so this is a 0 byte op. The
+                * hardware cannot handle a 0 byte op, so just ECB to
+                * generate the hash.
+                */
+               rc = nx_xcbc_empty(desc, out);
                goto out;
        }
 
@@ -211,6 +307,7 @@ static int nx_xcbc_final(struct shash_desc *desc, u8 *out)
 
        memcpy(out, csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
 out:
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return rc;
 }
 
index 67024f2f0b78746bdbfcb8c5ffde595754a0b155..da0b24a7633f0c55626d6c9ecefe8211c7ef7817 100644 (file)
@@ -55,71 +55,91 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
        struct nx_sg *in_sg;
-       u64 to_process, leftover;
+       u64 to_process, leftover, total;
+       u32 max_sg_len;
+       unsigned long irq_flags;
        int rc = 0;
 
-       if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
-               /* we've hit the nx chip previously and we're updating again,
-                * so copy over the partial digest */
-               memcpy(csbcpb->cpb.sha256.input_partial_digest,
-                      csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
-       }
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
 
        /* 2 cases for total data len:
-        *  1: <= SHA256_BLOCK_SIZE: copy into state, return 0
-        *  2: > SHA256_BLOCK_SIZE: process X blocks, copy in leftover
+        *  1: < SHA256_BLOCK_SIZE: copy into state, return 0
+        *  2: >= SHA256_BLOCK_SIZE: process X blocks, copy in leftover
         */
-       if (len + sctx->count < SHA256_BLOCK_SIZE) {
+       total = sctx->count + len;
+       if (total < SHA256_BLOCK_SIZE) {
                memcpy(sctx->buf + sctx->count, data, len);
                sctx->count += len;
                goto out;
        }
 
-       /* to_process: the SHA256_BLOCK_SIZE data chunk to process in this
-        * update */
-       to_process = (sctx->count + len) & ~(SHA256_BLOCK_SIZE - 1);
-       leftover = (sctx->count + len) & (SHA256_BLOCK_SIZE - 1);
-
-       if (sctx->count) {
-               in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
-                                        sctx->count, nx_ctx->ap->sglen);
-               in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+       in_sg = nx_ctx->in_sg;
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg),
+                          nx_ctx->ap->sglen);
+
+       do {
+               /*
+                * to_process: the SHA256_BLOCK_SIZE data chunk to process in
+                * this update. This value is also restricted by the sg list
+                * limits.
+                */
+               to_process = min_t(u64, total, nx_ctx->ap->databytelen);
+               to_process = min_t(u64, to_process,
+                                  NX_PAGE_SIZE * (max_sg_len - 1));
+               to_process = to_process & ~(SHA256_BLOCK_SIZE - 1);
+               leftover = total - to_process;
+
+               if (sctx->count) {
+                       in_sg = nx_build_sg_list(nx_ctx->in_sg,
+                                                (u8 *) sctx->buf,
+                                                sctx->count, max_sg_len);
+               }
+               in_sg = nx_build_sg_list(in_sg, (u8 *) data,
                                         to_process - sctx->count,
-                                        nx_ctx->ap->sglen);
+                                        max_sg_len);
                nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
                                        sizeof(struct nx_sg);
-       } else {
-               in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data,
-                                        to_process, nx_ctx->ap->sglen);
-               nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
-                                       sizeof(struct nx_sg);
-       }
 
-       NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+               if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+                       /*
+                        * we've hit the nx chip previously and we're updating
+                        * again, so copy over the partial digest.
+                        */
+                       memcpy(csbcpb->cpb.sha256.input_partial_digest,
+                              csbcpb->cpb.sha256.message_digest,
+                              SHA256_DIGEST_SIZE);
+               }
 
-       if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
-               rc = -EINVAL;
-               goto out;
-       }
+               NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+               if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+                       rc = -EINVAL;
+                       goto out;
+               }
 
-       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
-                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
-       if (rc)
-               goto out;
+               rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                                  desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+               if (rc)
+                       goto out;
 
-       atomic_inc(&(nx_ctx->stats->sha256_ops));
+               atomic_inc(&(nx_ctx->stats->sha256_ops));
+               csbcpb->cpb.sha256.message_bit_length += (u64)
+                       (csbcpb->cpb.sha256.spbc * 8);
+
+               /* everything after the first update is continuation */
+               NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+
+               total -= to_process;
+               data += to_process - sctx->count;
+               sctx->count = 0;
+               in_sg = nx_ctx->in_sg;
+       } while (leftover >= SHA256_BLOCK_SIZE);
 
        /* copy the leftover back into the state struct */
        if (leftover)
-               memcpy(sctx->buf, data + len - leftover, leftover);
+               memcpy(sctx->buf, data, leftover);
        sctx->count = leftover;
-
-       csbcpb->cpb.sha256.message_bit_length += (u64)
-               (csbcpb->cpb.sha256.spbc * 8);
-
-       /* everything after the first update is continuation */
-       NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
 out:
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return rc;
 }
 
@@ -129,8 +149,13 @@ static int nx_sha256_final(struct shash_desc *desc, u8 *out)
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
        struct nx_sg *in_sg, *out_sg;
+       u32 max_sg_len;
+       unsigned long irq_flags;
        int rc;
 
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
+
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len, nx_ctx->ap->sglen);
 
        if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
                /* we've hit the nx chip previously, now we're finalizing,
@@ -146,9 +171,9 @@ static int nx_sha256_final(struct shash_desc *desc, u8 *out)
        csbcpb->cpb.sha256.message_bit_length += (u64)(sctx->count * 8);
 
        in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
-                                sctx->count, nx_ctx->ap->sglen);
+                                sctx->count, max_sg_len);
        out_sg = nx_build_sg_list(nx_ctx->out_sg, out, SHA256_DIGEST_SIZE,
-                                 nx_ctx->ap->sglen);
+                                 max_sg_len);
        nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
        nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
 
@@ -168,6 +193,7 @@ static int nx_sha256_final(struct shash_desc *desc, u8 *out)
                     &(nx_ctx->stats->sha256_bytes));
        memcpy(out, csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
 out:
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return rc;
 }
 
@@ -177,6 +203,9 @@ static int nx_sha256_export(struct shash_desc *desc, void *out)
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
        struct sha256_state *octx = out;
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
 
        octx->count = sctx->count +
                      (csbcpb->cpb.sha256.message_bit_length / 8);
@@ -199,6 +228,7 @@ static int nx_sha256_export(struct shash_desc *desc, void *out)
                octx->state[7] = SHA256_H7;
        }
 
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return 0;
 }
 
@@ -208,6 +238,9 @@ static int nx_sha256_import(struct shash_desc *desc, const void *in)
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
        const struct sha256_state *ictx = in;
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
 
        memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
 
@@ -222,6 +255,7 @@ static int nx_sha256_import(struct shash_desc *desc, const void *in)
                NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
        }
 
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return 0;
 }
 
index 08eee11223490c7a1a249a2f559f960e72e7af2c..4ae5b0f221d5306fa96c47b423cf143b0454504e 100644 (file)
@@ -55,73 +55,93 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
        struct nx_sg *in_sg;
-       u64 to_process, leftover, spbc_bits;
+       u64 to_process, leftover, total, spbc_bits;
+       u32 max_sg_len;
+       unsigned long irq_flags;
        int rc = 0;
 
-       if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
-               /* we've hit the nx chip previously and we're updating again,
-                * so copy over the partial digest */
-               memcpy(csbcpb->cpb.sha512.input_partial_digest,
-                      csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
-       }
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
 
        /* 2 cases for total data len:
-        *  1: <= SHA512_BLOCK_SIZE: copy into state, return 0
-        *  2: > SHA512_BLOCK_SIZE: process X blocks, copy in leftover
+        *  1: < SHA512_BLOCK_SIZE: copy into state, return 0
+        *  2: >= SHA512_BLOCK_SIZE: process X blocks, copy in leftover
         */
-       if ((u64)len + sctx->count[0] < SHA512_BLOCK_SIZE) {
+       total = sctx->count[0] + len;
+       if (total < SHA512_BLOCK_SIZE) {
                memcpy(sctx->buf + sctx->count[0], data, len);
                sctx->count[0] += len;
                goto out;
        }
 
-       /* to_process: the SHA512_BLOCK_SIZE data chunk to process in this
-        * update */
-       to_process = (sctx->count[0] + len) & ~(SHA512_BLOCK_SIZE - 1);
-       leftover = (sctx->count[0] + len) & (SHA512_BLOCK_SIZE - 1);
-
-       if (sctx->count[0]) {
-               in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
-                                        sctx->count[0], nx_ctx->ap->sglen);
-               in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+       in_sg = nx_ctx->in_sg;
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg),
+                          nx_ctx->ap->sglen);
+
+       do {
+               /*
+                * to_process: the SHA512_BLOCK_SIZE data chunk to process in
+                * this update. This value is also restricted by the sg list
+                * limits.
+                */
+               to_process = min_t(u64, total, nx_ctx->ap->databytelen);
+               to_process = min_t(u64, to_process,
+                                  NX_PAGE_SIZE * (max_sg_len - 1));
+               to_process = to_process & ~(SHA512_BLOCK_SIZE - 1);
+               leftover = total - to_process;
+
+               if (sctx->count[0]) {
+                       in_sg = nx_build_sg_list(nx_ctx->in_sg,
+                                                (u8 *) sctx->buf,
+                                                sctx->count[0], max_sg_len);
+               }
+               in_sg = nx_build_sg_list(in_sg, (u8 *) data,
                                         to_process - sctx->count[0],
-                                        nx_ctx->ap->sglen);
-               nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
-                                       sizeof(struct nx_sg);
-       } else {
-               in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data,
-                                        to_process, nx_ctx->ap->sglen);
+                                        max_sg_len);
                nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
                                        sizeof(struct nx_sg);
-       }
 
-       NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+               if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+                       /*
+                        * we've hit the nx chip previously and we're updating
+                        * again, so copy over the partial digest.
+                        */
+                       memcpy(csbcpb->cpb.sha512.input_partial_digest,
+                              csbcpb->cpb.sha512.message_digest,
+                              SHA512_DIGEST_SIZE);
+               }
 
-       if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
-               rc = -EINVAL;
-               goto out;
-       }
-
-       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
-                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
-       if (rc)
-               goto out;
+               NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+               if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+
+               rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                                  desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+               if (rc)
+                       goto out;
+
+               atomic_inc(&(nx_ctx->stats->sha512_ops));
+               spbc_bits = csbcpb->cpb.sha512.spbc * 8;
+               csbcpb->cpb.sha512.message_bit_length_lo += spbc_bits;
+               if (csbcpb->cpb.sha512.message_bit_length_lo < spbc_bits)
+                       csbcpb->cpb.sha512.message_bit_length_hi++;
+
+               /* everything after the first update is continuation */
+               NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
 
-       atomic_inc(&(nx_ctx->stats->sha512_ops));
+               total -= to_process;
+               data += to_process - sctx->count[0];
+               sctx->count[0] = 0;
+               in_sg = nx_ctx->in_sg;
+       } while (leftover >= SHA512_BLOCK_SIZE);
 
        /* copy the leftover back into the state struct */
        if (leftover)
-               memcpy(sctx->buf, data + len - leftover, leftover);
+               memcpy(sctx->buf, data, leftover);
        sctx->count[0] = leftover;
-
-       spbc_bits = csbcpb->cpb.sha512.spbc * 8;
-       csbcpb->cpb.sha512.message_bit_length_lo += spbc_bits;
-       if (csbcpb->cpb.sha512.message_bit_length_lo < spbc_bits)
-               csbcpb->cpb.sha512.message_bit_length_hi++;
-
-       /* everything after the first update is continuation */
-       NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
 out:
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return rc;
 }
 
@@ -131,9 +151,15 @@ static int nx_sha512_final(struct shash_desc *desc, u8 *out)
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
        struct nx_sg *in_sg, *out_sg;
+       u32 max_sg_len;
        u64 count0;
+       unsigned long irq_flags;
        int rc;
 
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
+
+       max_sg_len = min_t(u32, nx_driver.of.max_sg_len, nx_ctx->ap->sglen);
+
        if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
                /* we've hit the nx chip previously, now we're finalizing,
                 * so copy over the partial digest */
@@ -152,9 +178,9 @@ static int nx_sha512_final(struct shash_desc *desc, u8 *out)
                csbcpb->cpb.sha512.message_bit_length_hi++;
 
        in_sg = nx_build_sg_list(nx_ctx->in_sg, sctx->buf, sctx->count[0],
-                                nx_ctx->ap->sglen);
+                                max_sg_len);
        out_sg = nx_build_sg_list(nx_ctx->out_sg, out, SHA512_DIGEST_SIZE,
-                                 nx_ctx->ap->sglen);
+                                 max_sg_len);
        nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
        nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
 
@@ -174,6 +200,7 @@ static int nx_sha512_final(struct shash_desc *desc, u8 *out)
 
        memcpy(out, csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
 out:
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return rc;
 }
 
@@ -183,6 +210,9 @@ static int nx_sha512_export(struct shash_desc *desc, void *out)
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
        struct sha512_state *octx = out;
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
 
        /* move message_bit_length (128 bits) into count and convert its value
         * to bytes */
@@ -214,6 +244,7 @@ static int nx_sha512_export(struct shash_desc *desc, void *out)
                octx->state[7] = SHA512_H7;
        }
 
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return 0;
 }
 
@@ -223,6 +254,9 @@ static int nx_sha512_import(struct shash_desc *desc, const void *in)
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
        const struct sha512_state *ictx = in;
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&nx_ctx->lock, irq_flags);
 
        memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
        sctx->count[0] = ictx->count[0] & 0x3f;
@@ -240,6 +274,7 @@ static int nx_sha512_import(struct shash_desc *desc, const void *in)
                NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
        }
 
+       spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
        return 0;
 }
 
index bbdab6e5ccf08f75fcc23481dbb9d29a1df6cd69..5533fe31c90dff2acc68434b86a31d4497ad3553 100644 (file)
@@ -61,8 +61,7 @@ int nx_hcall_sync(struct nx_crypto_ctx *nx_ctx,
 
        do {
                rc = vio_h_cop_sync(viodev, op);
-       } while ((rc == -EBUSY && !may_sleep && retries--) ||
-                (rc == -EBUSY && may_sleep && cond_resched()));
+       } while (rc == -EBUSY && !may_sleep && retries--);
 
        if (rc) {
                dev_dbg(&viodev->dev, "vio_h_cop_sync failed: rc: %d "
@@ -114,13 +113,29 @@ struct nx_sg *nx_build_sg_list(struct nx_sg *sg_head,
         * have been described (or @sgmax elements have been written), the
         * loop ends. min_t is used to ensure @end_addr falls on the same page
         * as sg_addr, if not, we need to create another nx_sg element for the
-        * data on the next page */
+        * data on the next page.
+        *
+        * Also when using vmalloc'ed data, every time that a system page
+        * boundary is crossed the physical address needs to be re-calculated.
+        */
        for (sg = sg_head; sg_len < len; sg++) {
+               u64 next_page;
+
                sg->addr = sg_addr;
-               sg_addr = min_t(u64, NX_PAGE_NUM(sg_addr + NX_PAGE_SIZE), end_addr);
-               sg->len = sg_addr - sg->addr;
+               sg_addr = min_t(u64, NX_PAGE_NUM(sg_addr + NX_PAGE_SIZE),
+                               end_addr);
+
+               next_page = (sg->addr & PAGE_MASK) + PAGE_SIZE;
+               sg->len = min_t(u64, sg_addr, next_page) - sg->addr;
                sg_len += sg->len;
 
+               if (sg_addr >= next_page &&
+                               is_vmalloc_addr(start_addr + sg_len)) {
+                       sg_addr = page_to_phys(vmalloc_to_page(
+                                               start_addr + sg_len));
+                       end_addr = sg_addr + len - sg_len;
+               }
+
                if ((sg - sg_head) == sgmax) {
                        pr_err("nx: scatter/gather list overflow, pid: %d\n",
                               current->pid);
@@ -196,6 +211,8 @@ struct nx_sg *nx_walk_and_build(struct nx_sg       *nx_dst,
  * @dst: destination scatterlist
  * @src: source scatterlist
  * @nbytes: length of data described in the scatterlists
+ * @offset: number of bytes to fast-forward past at the beginning of
+ *          scatterlists.
  * @iv: destination for the iv data, if the algorithm requires it
  *
  * This is common code shared by all the AES algorithms. It uses the block
@@ -207,6 +224,7 @@ int nx_build_sg_lists(struct nx_crypto_ctx  *nx_ctx,
                      struct scatterlist    *dst,
                      struct scatterlist    *src,
                      unsigned int           nbytes,
+                     unsigned int           offset,
                      u8                    *iv)
 {
        struct nx_sg *nx_insg = nx_ctx->in_sg;
@@ -215,8 +233,10 @@ int nx_build_sg_lists(struct nx_crypto_ctx  *nx_ctx,
        if (iv)
                memcpy(iv, desc->info, AES_BLOCK_SIZE);
 
-       nx_insg = nx_walk_and_build(nx_insg, nx_ctx->ap->sglen, src, 0, nbytes);
-       nx_outsg = nx_walk_and_build(nx_outsg, nx_ctx->ap->sglen, dst, 0, nbytes);
+       nx_insg = nx_walk_and_build(nx_insg, nx_ctx->ap->sglen, src,
+                                   offset, nbytes);
+       nx_outsg = nx_walk_and_build(nx_outsg, nx_ctx->ap->sglen, dst,
+                                   offset, nbytes);
 
        /* these lengths should be negative, which will indicate to phyp that
         * the input and output parameters are scatterlists, not linear
@@ -235,6 +255,7 @@ int nx_build_sg_lists(struct nx_crypto_ctx  *nx_ctx,
  */
 void nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function)
 {
+       spin_lock_init(&nx_ctx->lock);
        memset(nx_ctx->kmem, 0, nx_ctx->kmem_len);
        nx_ctx->csbcpb->csb.valid |= NX_CSB_VALID_BIT;
 
index 3232b182dd28da33d2784cc4cb8aa577dd028fe6..befda07ca1da9e0978c59b9061cf79f2114bb9fb 100644 (file)
@@ -117,6 +117,7 @@ struct nx_ctr_priv {
 };
 
 struct nx_crypto_ctx {
+       spinlock_t lock;          /* synchronize access to the context */
        void *kmem;               /* unaligned, kmalloc'd buffer */
        size_t kmem_len;          /* length of kmem */
        struct nx_csbcpb *csbcpb; /* aligned page given to phyp @ hcall time */
@@ -155,7 +156,7 @@ int nx_hcall_sync(struct nx_crypto_ctx *ctx, struct vio_pfo_op *op,
 struct nx_sg *nx_build_sg_list(struct nx_sg *, u8 *, unsigned int, u32);
 int nx_build_sg_lists(struct nx_crypto_ctx *, struct blkcipher_desc *,
                      struct scatterlist *, struct scatterlist *, unsigned int,
-                     u8 *);
+                     unsigned int, u8 *);
 struct nx_sg *nx_walk_and_build(struct nx_sg *, unsigned int,
                                struct scatterlist *, unsigned int,
                                unsigned int);
index 5f7980586850e1bd88fd0ed3ac0ba9db1cb5b209..ce791c2f81f79e4ffda5d7d44e6a31a8a46bcb34 100644 (file)
@@ -13,7 +13,9 @@
  *
  */
 
-#define pr_fmt(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) "%20s: " fmt, __func__
+#define prn(num) pr_debug(#num "=%d\n", num)
+#define prx(num) pr_debug(#num "=%x\n", num)
 
 #include <linux/err.h>
 #include <linux/module.h>
@@ -38,6 +40,8 @@
 #define DST_MAXBURST                   4
 #define DMA_MIN                                (DST_MAXBURST * sizeof(u32))
 
+#define _calc_walked(inout) (dd->inout##_walk.offset - dd->inout##_sg->offset)
+
 /* OMAP TRM gives bitfields as start:end, where start is the higher bit
    number. For example 7:0 */
 #define FLD_MASK(start, end)   (((1 << ((start) - (end) + 1)) - 1) << (end))
 
 #define AES_REG_LENGTH_N(x)            (0x54 + ((x) * 0x04))
 
+#define AES_REG_IRQ_STATUS(dd)         ((dd)->pdata->irq_status_ofs)
+#define AES_REG_IRQ_ENABLE(dd)         ((dd)->pdata->irq_enable_ofs)
+#define AES_REG_IRQ_DATA_IN            BIT(1)
+#define AES_REG_IRQ_DATA_OUT           BIT(2)
 #define DEFAULT_TIMEOUT                (5*HZ)
 
 #define FLAGS_MODE_MASK                0x000f
@@ -86,6 +94,8 @@
 #define FLAGS_FAST             BIT(5)
 #define FLAGS_BUSY             BIT(6)
 
+#define AES_BLOCK_WORDS                (AES_BLOCK_SIZE >> 2)
+
 struct omap_aes_ctx {
        struct omap_aes_dev *dd;
 
@@ -119,6 +129,8 @@ struct omap_aes_pdata {
        u32             data_ofs;
        u32             rev_ofs;
        u32             mask_ofs;
+       u32             irq_enable_ofs;
+       u32             irq_status_ofs;
 
        u32             dma_enable_in;
        u32             dma_enable_out;
@@ -146,25 +158,32 @@ struct omap_aes_dev {
        struct tasklet_struct   queue_task;
 
        struct ablkcipher_request       *req;
+
+       /*
+        * total is used by PIO mode for book keeping so introduce
+        * variable total_save as need it to calc page_order
+        */
        size_t                          total;
+       size_t                          total_save;
+
        struct scatterlist              *in_sg;
-       struct scatterlist              in_sgl;
-       size_t                          in_offset;
        struct scatterlist              *out_sg;
+
+       /* Buffers for copying for unaligned cases */
+       struct scatterlist              in_sgl;
        struct scatterlist              out_sgl;
-       size_t                          out_offset;
+       struct scatterlist              *orig_out;
+       int                             sgs_copied;
 
-       size_t                  buflen;
-       void                    *buf_in;
-       size_t                  dma_size;
+       struct scatter_walk             in_walk;
+       struct scatter_walk             out_walk;
        int                     dma_in;
        struct dma_chan         *dma_lch_in;
-       dma_addr_t              dma_addr_in;
-       void                    *buf_out;
        int                     dma_out;
        struct dma_chan         *dma_lch_out;
-       dma_addr_t              dma_addr_out;
-
+       int                     in_sg_len;
+       int                     out_sg_len;
+       int                     pio_only;
        const struct omap_aes_pdata     *pdata;
 };
 
@@ -172,16 +191,36 @@ struct omap_aes_dev {
 static LIST_HEAD(dev_list);
 static DEFINE_SPINLOCK(list_lock);
 
+#ifdef DEBUG
+#define omap_aes_read(dd, offset)                              \
+({                                                             \
+       int _read_ret;                                          \
+       _read_ret = __raw_readl(dd->io_base + offset);          \
+       pr_debug("omap_aes_read(" #offset "=%#x)= %#x\n",       \
+                offset, _read_ret);                            \
+       _read_ret;                                              \
+})
+#else
 static inline u32 omap_aes_read(struct omap_aes_dev *dd, u32 offset)
 {
        return __raw_readl(dd->io_base + offset);
 }
+#endif
 
+#ifdef DEBUG
+#define omap_aes_write(dd, offset, value)                              \
+       do {                                                            \
+               pr_debug("omap_aes_write(" #offset "=%#x) value=%#x\n", \
+                        offset, value);                                \
+               __raw_writel(value, dd->io_base + offset);              \
+       } while (0)
+#else
 static inline void omap_aes_write(struct omap_aes_dev *dd, u32 offset,
                                  u32 value)
 {
        __raw_writel(value, dd->io_base + offset);
 }
+#endif
 
 static inline void omap_aes_write_mask(struct omap_aes_dev *dd, u32 offset,
                                        u32 value, u32 mask)
@@ -323,33 +362,6 @@ static int omap_aes_dma_init(struct omap_aes_dev *dd)
        dd->dma_lch_out = NULL;
        dd->dma_lch_in = NULL;
 
-       dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE);
-       dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE);
-       dd->buflen = PAGE_SIZE << OMAP_AES_CACHE_SIZE;
-       dd->buflen &= ~(AES_BLOCK_SIZE - 1);
-
-       if (!dd->buf_in || !dd->buf_out) {
-               dev_err(dd->dev, "unable to alloc pages.\n");
-               goto err_alloc;
-       }
-
-       /* MAP here */
-       dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in, dd->buflen,
-                                        DMA_TO_DEVICE);
-       if (dma_mapping_error(dd->dev, dd->dma_addr_in)) {
-               dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
-               err = -EINVAL;
-               goto err_map_in;
-       }
-
-       dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out, dd->buflen,
-                                         DMA_FROM_DEVICE);
-       if (dma_mapping_error(dd->dev, dd->dma_addr_out)) {
-               dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
-               err = -EINVAL;
-               goto err_map_out;
-       }
-
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
@@ -376,14 +388,6 @@ static int omap_aes_dma_init(struct omap_aes_dev *dd)
 err_dma_out:
        dma_release_channel(dd->dma_lch_in);
 err_dma_in:
-       dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
-                        DMA_FROM_DEVICE);
-err_map_out:
-       dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE);
-err_map_in:
-       free_pages((unsigned long)dd->buf_out, OMAP_AES_CACHE_SIZE);
-       free_pages((unsigned long)dd->buf_in, OMAP_AES_CACHE_SIZE);
-err_alloc:
        if (err)
                pr_err("error: %d\n", err);
        return err;
@@ -393,11 +397,6 @@ static void omap_aes_dma_cleanup(struct omap_aes_dev *dd)
 {
        dma_release_channel(dd->dma_lch_out);
        dma_release_channel(dd->dma_lch_in);
-       dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
-                        DMA_FROM_DEVICE);
-       dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE);
-       free_pages((unsigned long)dd->buf_out, OMAP_AES_CACHE_SIZE);
-       free_pages((unsigned long)dd->buf_in, OMAP_AES_CACHE_SIZE);
 }
 
 static void sg_copy_buf(void *buf, struct scatterlist *sg,
@@ -414,59 +413,27 @@ static void sg_copy_buf(void *buf, struct scatterlist *sg,
        scatterwalk_done(&walk, out, 0);
 }
 
-static int sg_copy(struct scatterlist **sg, size_t *offset, void *buf,
-                  size_t buflen, size_t total, int out)
-{
-       unsigned int count, off = 0;
-
-       while (buflen && total) {
-               count = min((*sg)->length - *offset, total);
-               count = min(count, buflen);
-
-               if (!count)
-                       return off;
-
-               /*
-                * buflen and total are AES_BLOCK_SIZE size aligned,
-                * so count should be also aligned
-                */
-
-               sg_copy_buf(buf + off, *sg, *offset, count, out);
-
-               off += count;
-               buflen -= count;
-               *offset += count;
-               total -= count;
-
-               if (*offset == (*sg)->length) {
-                       *sg = sg_next(*sg);
-                       if (*sg)
-                               *offset = 0;
-                       else
-                               total = 0;
-               }
-       }
-
-       return off;
-}
-
 static int omap_aes_crypt_dma(struct crypto_tfm *tfm,
-               struct scatterlist *in_sg, struct scatterlist *out_sg)
+               struct scatterlist *in_sg, struct scatterlist *out_sg,
+               int in_sg_len, int out_sg_len)
 {
        struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm);
        struct omap_aes_dev *dd = ctx->dd;
        struct dma_async_tx_descriptor *tx_in, *tx_out;
        struct dma_slave_config cfg;
-       dma_addr_t dma_addr_in = sg_dma_address(in_sg);
-       int ret, length = sg_dma_len(in_sg);
+       int ret;
 
-       pr_debug("len: %d\n", length);
+       if (dd->pio_only) {
+               scatterwalk_start(&dd->in_walk, dd->in_sg);
+               scatterwalk_start(&dd->out_walk, dd->out_sg);
 
-       dd->dma_size = length;
+               /* Enable DATAIN interrupt and let it take
+                  care of the rest */
+               omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x2);
+               return 0;
+       }
 
-       if (!(dd->flags & FLAGS_FAST))
-               dma_sync_single_for_device(dd->dev, dma_addr_in, length,
-                                          DMA_TO_DEVICE);
+       dma_sync_sg_for_device(dd->dev, dd->in_sg, in_sg_len, DMA_TO_DEVICE);
 
        memset(&cfg, 0, sizeof(cfg));
 
@@ -485,7 +452,7 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm,
                return ret;
        }
 
-       tx_in = dmaengine_prep_slave_sg(dd->dma_lch_in, in_sg, 1,
+       tx_in = dmaengine_prep_slave_sg(dd->dma_lch_in, in_sg, in_sg_len,
                                        DMA_MEM_TO_DEV,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!tx_in) {
@@ -504,7 +471,7 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm,
                return ret;
        }
 
-       tx_out = dmaengine_prep_slave_sg(dd->dma_lch_out, out_sg, 1,
+       tx_out = dmaengine_prep_slave_sg(dd->dma_lch_out, out_sg, out_sg_len,
                                        DMA_DEV_TO_MEM,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!tx_out) {
@@ -522,7 +489,7 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm,
        dma_async_issue_pending(dd->dma_lch_out);
 
        /* start DMA */
-       dd->pdata->trigger(dd, length);
+       dd->pdata->trigger(dd, dd->total);
 
        return 0;
 }
@@ -531,93 +498,32 @@ static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd)
 {
        struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
                                        crypto_ablkcipher_reqtfm(dd->req));
-       int err, fast = 0, in, out;
-       size_t count;
-       dma_addr_t addr_in, addr_out;
-       struct scatterlist *in_sg, *out_sg;
-       int len32;
+       int err;
 
        pr_debug("total: %d\n", dd->total);
 
-       if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) {
-               /* check for alignment */
-               in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32));
-               out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32));
-
-               fast = in && out;
-       }
-
-       if (fast)  {
-               count = min(dd->total, sg_dma_len(dd->in_sg));
-               count = min(count, sg_dma_len(dd->out_sg));
-
-               if (count != dd->total) {
-                       pr_err("request length != buffer length\n");
-                       return -EINVAL;
-               }
-
-               pr_debug("fast\n");
-
-               err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+       if (!dd->pio_only) {
+               err = dma_map_sg(dd->dev, dd->in_sg, dd->in_sg_len,
+                                DMA_TO_DEVICE);
                if (!err) {
                        dev_err(dd->dev, "dma_map_sg() error\n");
                        return -EINVAL;
                }
 
-               err = dma_map_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
+               err = dma_map_sg(dd->dev, dd->out_sg, dd->out_sg_len,
+                                DMA_FROM_DEVICE);
                if (!err) {
                        dev_err(dd->dev, "dma_map_sg() error\n");
-                       dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
                        return -EINVAL;
                }
-
-               addr_in = sg_dma_address(dd->in_sg);
-               addr_out = sg_dma_address(dd->out_sg);
-
-               in_sg = dd->in_sg;
-               out_sg = dd->out_sg;
-
-               dd->flags |= FLAGS_FAST;
-
-       } else {
-               /* use cache buffers */
-               count = sg_copy(&dd->in_sg, &dd->in_offset, dd->buf_in,
-                                dd->buflen, dd->total, 0);
-
-               len32 = DIV_ROUND_UP(count, DMA_MIN) * DMA_MIN;
-
-               /*
-                * The data going into the AES module has been copied
-                * to a local buffer and the data coming out will go
-                * into a local buffer so set up local SG entries for
-                * both.
-                */
-               sg_init_table(&dd->in_sgl, 1);
-               dd->in_sgl.offset = dd->in_offset;
-               sg_dma_len(&dd->in_sgl) = len32;
-               sg_dma_address(&dd->in_sgl) = dd->dma_addr_in;
-
-               sg_init_table(&dd->out_sgl, 1);
-               dd->out_sgl.offset = dd->out_offset;
-               sg_dma_len(&dd->out_sgl) = len32;
-               sg_dma_address(&dd->out_sgl) = dd->dma_addr_out;
-
-               in_sg = &dd->in_sgl;
-               out_sg = &dd->out_sgl;
-
-               addr_in = dd->dma_addr_in;
-               addr_out = dd->dma_addr_out;
-
-               dd->flags &= ~FLAGS_FAST;
-
        }
 
-       dd->total -= count;
-
-       err = omap_aes_crypt_dma(tfm, in_sg, out_sg);
-       if (err) {
-               dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
-               dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
+       err = omap_aes_crypt_dma(tfm, dd->in_sg, dd->out_sg, dd->in_sg_len,
+                                dd->out_sg_len);
+       if (err && !dd->pio_only) {
+               dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
+               dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len,
+                            DMA_FROM_DEVICE);
        }
 
        return err;
@@ -637,7 +543,6 @@ static void omap_aes_finish_req(struct omap_aes_dev *dd, int err)
 static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd)
 {
        int err = 0;
-       size_t count;
 
        pr_debug("total: %d\n", dd->total);
 
@@ -646,23 +551,49 @@ static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd)
        dmaengine_terminate_all(dd->dma_lch_in);
        dmaengine_terminate_all(dd->dma_lch_out);
 
-       if (dd->flags & FLAGS_FAST) {
-               dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
-               dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
-       } else {
-               dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
-                                          dd->dma_size, DMA_FROM_DEVICE);
-
-               /* copy data */
-               count = sg_copy(&dd->out_sg, &dd->out_offset, dd->buf_out,
-                                dd->buflen, dd->dma_size, 1);
-               if (count != dd->dma_size) {
-                       err = -EINVAL;
-                       pr_err("not all data converted: %u\n", count);
-               }
+       return err;
+}
+
+int omap_aes_check_aligned(struct scatterlist *sg)
+{
+       while (sg) {
+               if (!IS_ALIGNED(sg->offset, 4))
+                       return -1;
+               if (!IS_ALIGNED(sg->length, AES_BLOCK_SIZE))
+                       return -1;
+               sg = sg_next(sg);
        }
+       return 0;
+}
 
-       return err;
+int omap_aes_copy_sgs(struct omap_aes_dev *dd)
+{
+       void *buf_in, *buf_out;
+       int pages;
+
+       pages = get_order(dd->total);
+
+       buf_in = (void *)__get_free_pages(GFP_ATOMIC, pages);
+       buf_out = (void *)__get_free_pages(GFP_ATOMIC, pages);
+
+       if (!buf_in || !buf_out) {
+               pr_err("Couldn't allocated pages for unaligned cases.\n");
+               return -1;
+       }
+
+       dd->orig_out = dd->out_sg;
+
+       sg_copy_buf(buf_in, dd->in_sg, 0, dd->total, 0);
+
+       sg_init_table(&dd->in_sgl, 1);
+       sg_set_buf(&dd->in_sgl, buf_in, dd->total);
+       dd->in_sg = &dd->in_sgl;
+
+       sg_init_table(&dd->out_sgl, 1);
+       sg_set_buf(&dd->out_sgl, buf_out, dd->total);
+       dd->out_sg = &dd->out_sgl;
+
+       return 0;
 }
 
 static int omap_aes_handle_queue(struct omap_aes_dev *dd,
@@ -698,11 +629,23 @@ static int omap_aes_handle_queue(struct omap_aes_dev *dd,
        /* assign new request to device */
        dd->req = req;
        dd->total = req->nbytes;
-       dd->in_offset = 0;
+       dd->total_save = req->nbytes;
        dd->in_sg = req->src;
-       dd->out_offset = 0;
        dd->out_sg = req->dst;
 
+       if (omap_aes_check_aligned(dd->in_sg) ||
+           omap_aes_check_aligned(dd->out_sg)) {
+               if (omap_aes_copy_sgs(dd))
+                       pr_err("Failed to copy SGs for unaligned cases\n");
+               dd->sgs_copied = 1;
+       } else {
+               dd->sgs_copied = 0;
+       }
+
+       dd->in_sg_len = scatterwalk_bytes_sglen(dd->in_sg, dd->total);
+       dd->out_sg_len = scatterwalk_bytes_sglen(dd->out_sg, dd->total);
+       BUG_ON(dd->in_sg_len < 0 || dd->out_sg_len < 0);
+
        rctx = ablkcipher_request_ctx(req);
        ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
        rctx->mode &= FLAGS_MODE_MASK;
@@ -726,21 +669,32 @@ static int omap_aes_handle_queue(struct omap_aes_dev *dd,
 static void omap_aes_done_task(unsigned long data)
 {
        struct omap_aes_dev *dd = (struct omap_aes_dev *)data;
-       int err;
-
-       pr_debug("enter\n");
+       void *buf_in, *buf_out;
+       int pages;
+
+       pr_debug("enter done_task\n");
+
+       if (!dd->pio_only) {
+               dma_sync_sg_for_device(dd->dev, dd->out_sg, dd->out_sg_len,
+                                      DMA_FROM_DEVICE);
+               dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
+               dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len,
+                            DMA_FROM_DEVICE);
+               omap_aes_crypt_dma_stop(dd);
+       }
 
-       err = omap_aes_crypt_dma_stop(dd);
+       if (dd->sgs_copied) {
+               buf_in = sg_virt(&dd->in_sgl);
+               buf_out = sg_virt(&dd->out_sgl);
 
-       err = dd->err ? : err;
+               sg_copy_buf(buf_out, dd->orig_out, 0, dd->total_save, 1);
 
-       if (dd->total && !err) {
-               err = omap_aes_crypt_dma_start(dd);
-               if (!err)
-                       return; /* DMA started. Not fininishing. */
+               pages = get_order(dd->total_save);
+               free_pages((unsigned long)buf_in, pages);
+               free_pages((unsigned long)buf_out, pages);
        }
 
-       omap_aes_finish_req(dd, err);
+       omap_aes_finish_req(dd, 0);
        omap_aes_handle_queue(dd, NULL);
 
        pr_debug("exit\n");
@@ -1002,6 +956,8 @@ static const struct omap_aes_pdata omap_aes_pdata_omap4 = {
        .data_ofs       = 0x60,
        .rev_ofs        = 0x80,
        .mask_ofs       = 0x84,
+       .irq_status_ofs = 0x8c,
+       .irq_enable_ofs = 0x90,
        .dma_enable_in  = BIT(5),
        .dma_enable_out = BIT(6),
        .major_mask     = 0x0700,
@@ -1010,6 +966,90 @@ static const struct omap_aes_pdata omap_aes_pdata_omap4 = {
        .minor_shift    = 0,
 };
 
+static irqreturn_t omap_aes_irq(int irq, void *dev_id)
+{
+       struct omap_aes_dev *dd = dev_id;
+       u32 status, i;
+       u32 *src, *dst;
+
+       status = omap_aes_read(dd, AES_REG_IRQ_STATUS(dd));
+       if (status & AES_REG_IRQ_DATA_IN) {
+               omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x0);
+
+               BUG_ON(!dd->in_sg);
+
+               BUG_ON(_calc_walked(in) > dd->in_sg->length);
+
+               src = sg_virt(dd->in_sg) + _calc_walked(in);
+
+               for (i = 0; i < AES_BLOCK_WORDS; i++) {
+                       omap_aes_write(dd, AES_REG_DATA_N(dd, i), *src);
+
+                       scatterwalk_advance(&dd->in_walk, 4);
+                       if (dd->in_sg->length == _calc_walked(in)) {
+                               dd->in_sg = scatterwalk_sg_next(dd->in_sg);
+                               if (dd->in_sg) {
+                                       scatterwalk_start(&dd->in_walk,
+                                                         dd->in_sg);
+                                       src = sg_virt(dd->in_sg) +
+                                             _calc_walked(in);
+                               }
+                       } else {
+                               src++;
+                       }
+               }
+
+               /* Clear IRQ status */
+               status &= ~AES_REG_IRQ_DATA_IN;
+               omap_aes_write(dd, AES_REG_IRQ_STATUS(dd), status);
+
+               /* Enable DATA_OUT interrupt */
+               omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x4);
+
+       } else if (status & AES_REG_IRQ_DATA_OUT) {
+               omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x0);
+
+               BUG_ON(!dd->out_sg);
+
+               BUG_ON(_calc_walked(out) > dd->out_sg->length);
+
+               dst = sg_virt(dd->out_sg) + _calc_walked(out);
+
+               for (i = 0; i < AES_BLOCK_WORDS; i++) {
+                       *dst = omap_aes_read(dd, AES_REG_DATA_N(dd, i));
+                       scatterwalk_advance(&dd->out_walk, 4);
+                       if (dd->out_sg->length == _calc_walked(out)) {
+                               dd->out_sg = scatterwalk_sg_next(dd->out_sg);
+                               if (dd->out_sg) {
+                                       scatterwalk_start(&dd->out_walk,
+                                                         dd->out_sg);
+                                       dst = sg_virt(dd->out_sg) +
+                                             _calc_walked(out);
+                               }
+                       } else {
+                               dst++;
+                       }
+               }
+
+               dd->total -= AES_BLOCK_SIZE;
+
+               BUG_ON(dd->total < 0);
+
+               /* Clear IRQ status */
+               status &= ~AES_REG_IRQ_DATA_OUT;
+               omap_aes_write(dd, AES_REG_IRQ_STATUS(dd), status);
+
+               if (!dd->total)
+                       /* All bytes read! */
+                       tasklet_schedule(&dd->done_task);
+               else
+                       /* Enable DATA_IN interrupt for next block */
+                       omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x2);
+       }
+
+       return IRQ_HANDLED;
+}
+
 static const struct of_device_id omap_aes_of_match[] = {
        {
                .compatible     = "ti,omap2-aes",
@@ -1115,10 +1155,10 @@ static int omap_aes_probe(struct platform_device *pdev)
        struct omap_aes_dev *dd;
        struct crypto_alg *algp;
        struct resource res;
-       int err = -ENOMEM, i, j;
+       int err = -ENOMEM, i, j, irq = -1;
        u32 reg;
 
-       dd = kzalloc(sizeof(struct omap_aes_dev), GFP_KERNEL);
+       dd = devm_kzalloc(dev, sizeof(struct omap_aes_dev), GFP_KERNEL);
        if (dd == NULL) {
                dev_err(dev, "unable to alloc data struct.\n");
                goto err_data;
@@ -1158,8 +1198,23 @@ static int omap_aes_probe(struct platform_device *pdev)
        tasklet_init(&dd->queue_task, omap_aes_queue_task, (unsigned long)dd);
 
        err = omap_aes_dma_init(dd);
-       if (err)
-               goto err_dma;
+       if (err && AES_REG_IRQ_STATUS(dd) && AES_REG_IRQ_ENABLE(dd)) {
+               dd->pio_only = 1;
+
+               irq = platform_get_irq(pdev, 0);
+               if (irq < 0) {
+                       dev_err(dev, "can't get IRQ resource\n");
+                       goto err_irq;
+               }
+
+               err = devm_request_irq(dev, irq, omap_aes_irq, 0,
+                               dev_name(dev), dd);
+               if (err) {
+                       dev_err(dev, "Unable to grab omap-aes IRQ\n");
+                       goto err_irq;
+               }
+       }
+
 
        INIT_LIST_HEAD(&dd->list);
        spin_lock(&list_lock);
@@ -1187,13 +1242,13 @@ err_algs:
                for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
                        crypto_unregister_alg(
                                        &dd->pdata->algs_info[i].algs_list[j]);
-       omap_aes_dma_cleanup(dd);
-err_dma:
+       if (!dd->pio_only)
+               omap_aes_dma_cleanup(dd);
+err_irq:
        tasklet_kill(&dd->done_task);
        tasklet_kill(&dd->queue_task);
        pm_runtime_disable(dev);
 err_res:
-       kfree(dd);
        dd = NULL;
 err_data:
        dev_err(dev, "initialization failed.\n");
@@ -1221,7 +1276,6 @@ static int omap_aes_remove(struct platform_device *pdev)
        tasklet_kill(&dd->queue_task);
        omap_aes_dma_cleanup(dd);
        pm_runtime_disable(dd->dev);
-       kfree(dd);
        dd = NULL;
 
        return 0;
index 4bb67652c2005ea46cf2677172665f8a261e58e3..8bdde57f6bb1d7050967351744571b352062f1e1 100644 (file)
 #include <crypto/hash.h>
 #include <crypto/internal/hash.h>
 
-#define SHA1_MD5_BLOCK_SIZE            SHA1_BLOCK_SIZE
 #define MD5_DIGEST_SIZE                        16
 
-#define DST_MAXBURST                   16
-#define DMA_MIN                                (DST_MAXBURST * sizeof(u32))
-
 #define SHA_REG_IDIGEST(dd, x)         ((dd)->pdata->idigest_ofs + ((x)*0x04))
 #define SHA_REG_DIN(dd, x)             ((dd)->pdata->din_ofs + ((x) * 0x04))
 #define SHA_REG_DIGCNT(dd)             ((dd)->pdata->digcnt_ofs)
 
-#define SHA_REG_ODIGEST(x)             (0x00 + ((x) * 0x04))
+#define SHA_REG_ODIGEST(dd, x)         ((dd)->pdata->odigest_ofs + (x * 0x04))
 
 #define SHA_REG_CTRL                   0x18
 #define SHA_REG_CTRL_LENGTH            (0xFFFFFFFF << 5)
 #define SHA_REG_SYSSTATUS(dd)          ((dd)->pdata->sysstatus_ofs)
 #define SHA_REG_SYSSTATUS_RESETDONE    (1 << 0)
 
-#define SHA_REG_MODE                   0x44
+#define SHA_REG_MODE(dd)               ((dd)->pdata->mode_ofs)
 #define SHA_REG_MODE_HMAC_OUTER_HASH   (1 << 7)
 #define SHA_REG_MODE_HMAC_KEY_PROC     (1 << 5)
 #define SHA_REG_MODE_CLOSE_HASH                (1 << 4)
 #define SHA_REG_MODE_ALGO_CONSTANT     (1 << 3)
-#define SHA_REG_MODE_ALGO_MASK         (3 << 1)
-#define                SHA_REG_MODE_ALGO_MD5_128       (0 << 1)
-#define                SHA_REG_MODE_ALGO_SHA1_160      (1 << 1)
-#define                SHA_REG_MODE_ALGO_SHA2_224      (2 << 1)
-#define                SHA_REG_MODE_ALGO_SHA2_256      (3 << 1)
 
-#define SHA_REG_LENGTH                 0x48
+#define SHA_REG_MODE_ALGO_MASK         (7 << 0)
+#define SHA_REG_MODE_ALGO_MD5_128      (0 << 1)
+#define SHA_REG_MODE_ALGO_SHA1_160     (1 << 1)
+#define SHA_REG_MODE_ALGO_SHA2_224     (2 << 1)
+#define SHA_REG_MODE_ALGO_SHA2_256     (3 << 1)
+#define SHA_REG_MODE_ALGO_SHA2_384     (1 << 0)
+#define SHA_REG_MODE_ALGO_SHA2_512     (3 << 0)
+
+#define SHA_REG_LENGTH(dd)             ((dd)->pdata->length_ofs)
 
 #define SHA_REG_IRQSTATUS              0x118
 #define SHA_REG_IRQSTATUS_CTX_RDY      (1 << 3)
 #define FLAGS_SG               17
 
 #define FLAGS_MODE_SHIFT       18
-#define FLAGS_MODE_MASK                (SHA_REG_MODE_ALGO_MASK                 \
-                                       << (FLAGS_MODE_SHIFT - 1))
-#define                FLAGS_MODE_MD5          (SHA_REG_MODE_ALGO_MD5_128      \
-                                               << (FLAGS_MODE_SHIFT - 1))
-#define                FLAGS_MODE_SHA1         (SHA_REG_MODE_ALGO_SHA1_160     \
-                                               << (FLAGS_MODE_SHIFT - 1))
-#define                FLAGS_MODE_SHA224       (SHA_REG_MODE_ALGO_SHA2_224     \
-                                               << (FLAGS_MODE_SHIFT - 1))
-#define                FLAGS_MODE_SHA256       (SHA_REG_MODE_ALGO_SHA2_256     \
-                                               << (FLAGS_MODE_SHIFT - 1))
-#define FLAGS_HMAC             20
-#define FLAGS_ERROR            21
+#define FLAGS_MODE_MASK                (SHA_REG_MODE_ALGO_MASK << FLAGS_MODE_SHIFT)
+#define FLAGS_MODE_MD5         (SHA_REG_MODE_ALGO_MD5_128 << FLAGS_MODE_SHIFT)
+#define FLAGS_MODE_SHA1                (SHA_REG_MODE_ALGO_SHA1_160 << FLAGS_MODE_SHIFT)
+#define FLAGS_MODE_SHA224      (SHA_REG_MODE_ALGO_SHA2_224 << FLAGS_MODE_SHIFT)
+#define FLAGS_MODE_SHA256      (SHA_REG_MODE_ALGO_SHA2_256 << FLAGS_MODE_SHIFT)
+#define FLAGS_MODE_SHA384      (SHA_REG_MODE_ALGO_SHA2_384 << FLAGS_MODE_SHIFT)
+#define FLAGS_MODE_SHA512      (SHA_REG_MODE_ALGO_SHA2_512 << FLAGS_MODE_SHIFT)
+
+#define FLAGS_HMAC             21
+#define FLAGS_ERROR            22
 
 #define OP_UPDATE              1
 #define OP_FINAL               2
@@ -145,7 +142,7 @@ struct omap_sham_reqctx {
        unsigned long           flags;
        unsigned long           op;
 
-       u8                      digest[SHA256_DIGEST_SIZE] OMAP_ALIGNED;
+       u8                      digest[SHA512_DIGEST_SIZE] OMAP_ALIGNED;
        size_t                  digcnt;
        size_t                  bufcnt;
        size_t                  buflen;
@@ -162,8 +159,8 @@ struct omap_sham_reqctx {
 
 struct omap_sham_hmac_ctx {
        struct crypto_shash     *shash;
-       u8                      ipad[SHA1_MD5_BLOCK_SIZE] OMAP_ALIGNED;
-       u8                      opad[SHA1_MD5_BLOCK_SIZE] OMAP_ALIGNED;
+       u8                      ipad[SHA512_BLOCK_SIZE] OMAP_ALIGNED;
+       u8                      opad[SHA512_BLOCK_SIZE] OMAP_ALIGNED;
 };
 
 struct omap_sham_ctx {
@@ -205,6 +202,8 @@ struct omap_sham_pdata {
        u32             rev_ofs;
        u32             mask_ofs;
        u32             sysstatus_ofs;
+       u32             mode_ofs;
+       u32             length_ofs;
 
        u32             major_mask;
        u32             major_shift;
@@ -223,6 +222,7 @@ struct omap_sham_dev {
        unsigned int            dma;
        struct dma_chan         *dma_lch;
        struct tasklet_struct   done_task;
+       u8                      polling_mode;
 
        unsigned long           flags;
        struct crypto_queue     queue;
@@ -306,9 +306,9 @@ static void omap_sham_copy_hash_omap4(struct ahash_request *req, int out)
                for (i = 0; i < dd->pdata->digest_size / sizeof(u32); i++) {
                        if (out)
                                opad[i] = omap_sham_read(dd,
-                                               SHA_REG_ODIGEST(i));
+                                               SHA_REG_ODIGEST(dd, i));
                        else
-                               omap_sham_write(dd, SHA_REG_ODIGEST(i),
+                               omap_sham_write(dd, SHA_REG_ODIGEST(dd, i),
                                                opad[i]);
                }
        }
@@ -342,6 +342,12 @@ static void omap_sham_copy_ready_hash(struct ahash_request *req)
        case FLAGS_MODE_SHA256:
                d = SHA256_DIGEST_SIZE / sizeof(u32);
                break;
+       case FLAGS_MODE_SHA384:
+               d = SHA384_DIGEST_SIZE / sizeof(u32);
+               break;
+       case FLAGS_MODE_SHA512:
+               d = SHA512_DIGEST_SIZE / sizeof(u32);
+               break;
        default:
                d = 0;
        }
@@ -404,6 +410,30 @@ static int omap_sham_poll_irq_omap2(struct omap_sham_dev *dd)
        return omap_sham_wait(dd, SHA_REG_CTRL, SHA_REG_CTRL_INPUT_READY);
 }
 
+static int get_block_size(struct omap_sham_reqctx *ctx)
+{
+       int d;
+
+       switch (ctx->flags & FLAGS_MODE_MASK) {
+       case FLAGS_MODE_MD5:
+       case FLAGS_MODE_SHA1:
+               d = SHA1_BLOCK_SIZE;
+               break;
+       case FLAGS_MODE_SHA224:
+       case FLAGS_MODE_SHA256:
+               d = SHA256_BLOCK_SIZE;
+               break;
+       case FLAGS_MODE_SHA384:
+       case FLAGS_MODE_SHA512:
+               d = SHA512_BLOCK_SIZE;
+               break;
+       default:
+               d = 0;
+       }
+
+       return d;
+}
+
 static void omap_sham_write_n(struct omap_sham_dev *dd, u32 offset,
                                    u32 *value, int count)
 {
@@ -422,20 +452,24 @@ static void omap_sham_write_ctrl_omap4(struct omap_sham_dev *dd, size_t length,
         * CLOSE_HASH only for the last one. Note that flags mode bits
         * correspond to algorithm encoding in mode register.
         */
-       val = (ctx->flags & FLAGS_MODE_MASK) >> (FLAGS_MODE_SHIFT - 1);
+       val = (ctx->flags & FLAGS_MODE_MASK) >> (FLAGS_MODE_SHIFT);
        if (!ctx->digcnt) {
                struct crypto_ahash *tfm = crypto_ahash_reqtfm(dd->req);
                struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
                struct omap_sham_hmac_ctx *bctx = tctx->base;
+               int bs, nr_dr;
 
                val |= SHA_REG_MODE_ALGO_CONSTANT;
 
                if (ctx->flags & BIT(FLAGS_HMAC)) {
+                       bs = get_block_size(ctx);
+                       nr_dr = bs / (2 * sizeof(u32));
                        val |= SHA_REG_MODE_HMAC_KEY_PROC;
-                       omap_sham_write_n(dd, SHA_REG_ODIGEST(0),
-                                         (u32 *)bctx->ipad,
-                                         SHA1_BLOCK_SIZE / sizeof(u32));
-                       ctx->digcnt += SHA1_BLOCK_SIZE;
+                       omap_sham_write_n(dd, SHA_REG_ODIGEST(dd, 0),
+                                         (u32 *)bctx->ipad, nr_dr);
+                       omap_sham_write_n(dd, SHA_REG_IDIGEST(dd, 0),
+                                         (u32 *)bctx->ipad + nr_dr, nr_dr);
+                       ctx->digcnt += bs;
                }
        }
 
@@ -451,7 +485,7 @@ static void omap_sham_write_ctrl_omap4(struct omap_sham_dev *dd, size_t length,
               SHA_REG_MODE_HMAC_KEY_PROC;
 
        dev_dbg(dd->dev, "ctrl: %08x, flags: %08lx\n", val, ctx->flags);
-       omap_sham_write_mask(dd, SHA_REG_MODE, val, mask);
+       omap_sham_write_mask(dd, SHA_REG_MODE(dd), val, mask);
        omap_sham_write(dd, SHA_REG_IRQENA, SHA_REG_IRQENA_OUTPUT_RDY);
        omap_sham_write_mask(dd, SHA_REG_MASK(dd),
                             SHA_REG_MASK_IT_EN |
@@ -461,7 +495,7 @@ static void omap_sham_write_ctrl_omap4(struct omap_sham_dev *dd, size_t length,
 
 static void omap_sham_trigger_omap4(struct omap_sham_dev *dd, size_t length)
 {
-       omap_sham_write(dd, SHA_REG_LENGTH, length);
+       omap_sham_write(dd, SHA_REG_LENGTH(dd), length);
 }
 
 static int omap_sham_poll_irq_omap4(struct omap_sham_dev *dd)
@@ -474,7 +508,7 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
                              size_t length, int final)
 {
        struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
-       int count, len32;
+       int count, len32, bs32, offset = 0;
        const u32 *buffer = (const u32 *)buf;
 
        dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n",
@@ -486,18 +520,23 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
        /* should be non-zero before next lines to disable clocks later */
        ctx->digcnt += length;
 
-       if (dd->pdata->poll_irq(dd))
-               return -ETIMEDOUT;
-
        if (final)
                set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */
 
        set_bit(FLAGS_CPU, &dd->flags);
 
        len32 = DIV_ROUND_UP(length, sizeof(u32));
+       bs32 = get_block_size(ctx) / sizeof(u32);
 
-       for (count = 0; count < len32; count++)
-               omap_sham_write(dd, SHA_REG_DIN(dd, count), buffer[count]);
+       while (len32) {
+               if (dd->pdata->poll_irq(dd))
+                       return -ETIMEDOUT;
+
+               for (count = 0; count < min(len32, bs32); count++, offset++)
+                       omap_sham_write(dd, SHA_REG_DIN(dd, count),
+                                       buffer[offset]);
+               len32 -= min(len32, bs32);
+       }
 
        return -EINPROGRESS;
 }
@@ -516,7 +555,7 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
        struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
        struct dma_async_tx_descriptor *tx;
        struct dma_slave_config cfg;
-       int len32, ret;
+       int len32, ret, dma_min = get_block_size(ctx);
 
        dev_dbg(dd->dev, "xmit_dma: digcnt: %d, length: %d, final: %d\n",
                                                ctx->digcnt, length, final);
@@ -525,7 +564,7 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
 
        cfg.dst_addr = dd->phys_base + SHA_REG_DIN(dd, 0);
        cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       cfg.dst_maxburst = DST_MAXBURST;
+       cfg.dst_maxburst = dma_min / DMA_SLAVE_BUSWIDTH_4_BYTES;
 
        ret = dmaengine_slave_config(dd->dma_lch, &cfg);
        if (ret) {
@@ -533,7 +572,7 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
                return ret;
        }
 
-       len32 = DIV_ROUND_UP(length, DMA_MIN) * DMA_MIN;
+       len32 = DIV_ROUND_UP(length, dma_min) * dma_min;
 
        if (is_sg) {
                /*
@@ -666,14 +705,14 @@ static int omap_sham_update_dma_slow(struct omap_sham_dev *dd)
 /* Start address alignment */
 #define SG_AA(sg)      (IS_ALIGNED(sg->offset, sizeof(u32)))
 /* SHA1 block size alignment */
-#define SG_SA(sg)      (IS_ALIGNED(sg->length, SHA1_MD5_BLOCK_SIZE))
+#define SG_SA(sg, bs)  (IS_ALIGNED(sg->length, bs))
 
 static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
 {
        struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
        unsigned int length, final, tail;
        struct scatterlist *sg;
-       int ret;
+       int ret, bs;
 
        if (!ctx->total)
                return 0;
@@ -687,30 +726,31 @@ static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
         * the dmaengine infrastructure will calculate that it needs
         * to transfer 0 frames which ultimately fails.
         */
-       if (ctx->total < (DST_MAXBURST * sizeof(u32)))
+       if (ctx->total < get_block_size(ctx))
                return omap_sham_update_dma_slow(dd);
 
        dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n",
                        ctx->digcnt, ctx->bufcnt, ctx->total);
 
        sg = ctx->sg;
+       bs = get_block_size(ctx);
 
        if (!SG_AA(sg))
                return omap_sham_update_dma_slow(dd);
 
-       if (!sg_is_last(sg) && !SG_SA(sg))
-               /* size is not SHA1_BLOCK_SIZE aligned */
+       if (!sg_is_last(sg) && !SG_SA(sg, bs))
+               /* size is not BLOCK_SIZE aligned */
                return omap_sham_update_dma_slow(dd);
 
        length = min(ctx->total, sg->length);
 
        if (sg_is_last(sg)) {
                if (!(ctx->flags & BIT(FLAGS_FINUP))) {
-                       /* not last sg must be SHA1_MD5_BLOCK_SIZE aligned */
-                       tail = length & (SHA1_MD5_BLOCK_SIZE - 1);
+                       /* not last sg must be BLOCK_SIZE aligned */
+                       tail = length & (bs - 1);
                        /* without finup() we need one block to close hash */
                        if (!tail)
-                               tail = SHA1_MD5_BLOCK_SIZE;
+                               tail = bs;
                        length -= tail;
                }
        }
@@ -737,13 +777,22 @@ static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
 static int omap_sham_update_cpu(struct omap_sham_dev *dd)
 {
        struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
-       int bufcnt;
+       int bufcnt, final;
+
+       if (!ctx->total)
+               return 0;
 
        omap_sham_append_sg(ctx);
+
+       final = (ctx->flags & BIT(FLAGS_FINUP)) && !ctx->total;
+
+       dev_dbg(dd->dev, "cpu: bufcnt: %u, digcnt: %d, final: %d\n",
+               ctx->bufcnt, ctx->digcnt, final);
+
        bufcnt = ctx->bufcnt;
        ctx->bufcnt = 0;
 
-       return omap_sham_xmit_cpu(dd, ctx->buffer, bufcnt, 1);
+       return omap_sham_xmit_cpu(dd, ctx->buffer, bufcnt, final);
 }
 
 static int omap_sham_update_dma_stop(struct omap_sham_dev *dd)
@@ -773,6 +822,7 @@ static int omap_sham_init(struct ahash_request *req)
        struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
        struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
        struct omap_sham_dev *dd = NULL, *tmp;
+       int bs = 0;
 
        spin_lock_bh(&sham.lock);
        if (!tctx->dd) {
@@ -796,15 +846,27 @@ static int omap_sham_init(struct ahash_request *req)
        switch (crypto_ahash_digestsize(tfm)) {
        case MD5_DIGEST_SIZE:
                ctx->flags |= FLAGS_MODE_MD5;
+               bs = SHA1_BLOCK_SIZE;
                break;
        case SHA1_DIGEST_SIZE:
                ctx->flags |= FLAGS_MODE_SHA1;
+               bs = SHA1_BLOCK_SIZE;
                break;
        case SHA224_DIGEST_SIZE:
                ctx->flags |= FLAGS_MODE_SHA224;
+               bs = SHA224_BLOCK_SIZE;
                break;
        case SHA256_DIGEST_SIZE:
                ctx->flags |= FLAGS_MODE_SHA256;
+               bs = SHA256_BLOCK_SIZE;
+               break;
+       case SHA384_DIGEST_SIZE:
+               ctx->flags |= FLAGS_MODE_SHA384;
+               bs = SHA384_BLOCK_SIZE;
+               break;
+       case SHA512_DIGEST_SIZE:
+               ctx->flags |= FLAGS_MODE_SHA512;
+               bs = SHA512_BLOCK_SIZE;
                break;
        }
 
@@ -816,8 +878,8 @@ static int omap_sham_init(struct ahash_request *req)
                if (!test_bit(FLAGS_AUTO_XOR, &dd->flags)) {
                        struct omap_sham_hmac_ctx *bctx = tctx->base;
 
-                       memcpy(ctx->buffer, bctx->ipad, SHA1_MD5_BLOCK_SIZE);
-                       ctx->bufcnt = SHA1_MD5_BLOCK_SIZE;
+                       memcpy(ctx->buffer, bctx->ipad, bs);
+                       ctx->bufcnt = bs;
                }
 
                ctx->flags |= BIT(FLAGS_HMAC);
@@ -853,8 +915,11 @@ static int omap_sham_final_req(struct omap_sham_dev *dd)
        struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
        int err = 0, use_dma = 1;
 
-       if (ctx->bufcnt <= DMA_MIN)
-               /* faster to handle last block with cpu */
+       if ((ctx->bufcnt <= get_block_size(ctx)) || dd->polling_mode)
+               /*
+                * faster to handle last block with cpu or
+                * use cpu when dma is not present.
+                */
                use_dma = 0;
 
        if (use_dma)
@@ -1006,6 +1071,8 @@ static int omap_sham_enqueue(struct ahash_request *req, unsigned int op)
 static int omap_sham_update(struct ahash_request *req)
 {
        struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
+       struct omap_sham_dev *dd = ctx->dd;
+       int bs = get_block_size(ctx);
 
        if (!req->nbytes)
                return 0;
@@ -1023,10 +1090,12 @@ static int omap_sham_update(struct ahash_request *req)
                        */
                        omap_sham_append_sg(ctx);
                        return 0;
-               } else if (ctx->bufcnt + ctx->total <= SHA1_MD5_BLOCK_SIZE) {
+               } else if ((ctx->bufcnt + ctx->total <= bs) ||
+                          dd->polling_mode) {
                        /*
-                       * faster to use CPU for short transfers
-                       */
+                        * faster to use CPU for short transfers or
+                        * use cpu when dma is not present.
+                        */
                        ctx->flags |= BIT(FLAGS_CPU);
                }
        } else if (ctx->bufcnt + ctx->total < ctx->buflen) {
@@ -1214,6 +1283,16 @@ static int omap_sham_cra_md5_init(struct crypto_tfm *tfm)
        return omap_sham_cra_init_alg(tfm, "md5");
 }
 
+static int omap_sham_cra_sha384_init(struct crypto_tfm *tfm)
+{
+       return omap_sham_cra_init_alg(tfm, "sha384");
+}
+
+static int omap_sham_cra_sha512_init(struct crypto_tfm *tfm)
+{
+       return omap_sham_cra_init_alg(tfm, "sha512");
+}
+
 static void omap_sham_cra_exit(struct crypto_tfm *tfm)
 {
        struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm);
@@ -1422,6 +1501,101 @@ static struct ahash_alg algs_sha224_sha256[] = {
 },
 };
 
+static struct ahash_alg algs_sha384_sha512[] = {
+{
+       .init           = omap_sham_init,
+       .update         = omap_sham_update,
+       .final          = omap_sham_final,
+       .finup          = omap_sham_finup,
+       .digest         = omap_sham_digest,
+       .halg.digestsize        = SHA384_DIGEST_SIZE,
+       .halg.base      = {
+               .cra_name               = "sha384",
+               .cra_driver_name        = "omap-sha384",
+               .cra_priority           = 100,
+               .cra_flags              = CRYPTO_ALG_TYPE_AHASH |
+                                               CRYPTO_ALG_ASYNC |
+                                               CRYPTO_ALG_NEED_FALLBACK,
+               .cra_blocksize          = SHA384_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct omap_sham_ctx),
+               .cra_alignmask          = 0,
+               .cra_module             = THIS_MODULE,
+               .cra_init               = omap_sham_cra_init,
+               .cra_exit               = omap_sham_cra_exit,
+       }
+},
+{
+       .init           = omap_sham_init,
+       .update         = omap_sham_update,
+       .final          = omap_sham_final,
+       .finup          = omap_sham_finup,
+       .digest         = omap_sham_digest,
+       .halg.digestsize        = SHA512_DIGEST_SIZE,
+       .halg.base      = {
+               .cra_name               = "sha512",
+               .cra_driver_name        = "omap-sha512",
+               .cra_priority           = 100,
+               .cra_flags              = CRYPTO_ALG_TYPE_AHASH |
+                                               CRYPTO_ALG_ASYNC |
+                                               CRYPTO_ALG_NEED_FALLBACK,
+               .cra_blocksize          = SHA512_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct omap_sham_ctx),
+               .cra_alignmask          = 0,
+               .cra_module             = THIS_MODULE,
+               .cra_init               = omap_sham_cra_init,
+               .cra_exit               = omap_sham_cra_exit,
+       }
+},
+{
+       .init           = omap_sham_init,
+       .update         = omap_sham_update,
+       .final          = omap_sham_final,
+       .finup          = omap_sham_finup,
+       .digest         = omap_sham_digest,
+       .setkey         = omap_sham_setkey,
+       .halg.digestsize        = SHA384_DIGEST_SIZE,
+       .halg.base      = {
+               .cra_name               = "hmac(sha384)",
+               .cra_driver_name        = "omap-hmac-sha384",
+               .cra_priority           = 100,
+               .cra_flags              = CRYPTO_ALG_TYPE_AHASH |
+                                               CRYPTO_ALG_ASYNC |
+                                               CRYPTO_ALG_NEED_FALLBACK,
+               .cra_blocksize          = SHA384_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct omap_sham_ctx) +
+                                       sizeof(struct omap_sham_hmac_ctx),
+               .cra_alignmask          = OMAP_ALIGN_MASK,
+               .cra_module             = THIS_MODULE,
+               .cra_init               = omap_sham_cra_sha384_init,
+               .cra_exit               = omap_sham_cra_exit,
+       }
+},
+{
+       .init           = omap_sham_init,
+       .update         = omap_sham_update,
+       .final          = omap_sham_final,
+       .finup          = omap_sham_finup,
+       .digest         = omap_sham_digest,
+       .setkey         = omap_sham_setkey,
+       .halg.digestsize        = SHA512_DIGEST_SIZE,
+       .halg.base      = {
+               .cra_name               = "hmac(sha512)",
+               .cra_driver_name        = "omap-hmac-sha512",
+               .cra_priority           = 100,
+               .cra_flags              = CRYPTO_ALG_TYPE_AHASH |
+                                               CRYPTO_ALG_ASYNC |
+                                               CRYPTO_ALG_NEED_FALLBACK,
+               .cra_blocksize          = SHA512_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct omap_sham_ctx) +
+                                       sizeof(struct omap_sham_hmac_ctx),
+               .cra_alignmask          = OMAP_ALIGN_MASK,
+               .cra_module             = THIS_MODULE,
+               .cra_init               = omap_sham_cra_sha512_init,
+               .cra_exit               = omap_sham_cra_exit,
+       }
+},
+};
+
 static void omap_sham_done_task(unsigned long data)
 {
        struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
@@ -1433,8 +1607,12 @@ static void omap_sham_done_task(unsigned long data)
        }
 
        if (test_bit(FLAGS_CPU, &dd->flags)) {
-               if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags))
-                       goto finish;
+               if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) {
+                       /* hash or semi-hash ready */
+                       err = omap_sham_update_cpu(dd);
+                       if (err != -EINPROGRESS)
+                               goto finish;
+               }
        } else if (test_bit(FLAGS_DMA_READY, &dd->flags)) {
                if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->flags)) {
                        omap_sham_update_dma_stop(dd);
@@ -1548,11 +1726,54 @@ static const struct omap_sham_pdata omap_sham_pdata_omap4 = {
        .poll_irq       = omap_sham_poll_irq_omap4,
        .intr_hdlr      = omap_sham_irq_omap4,
        .idigest_ofs    = 0x020,
+       .odigest_ofs    = 0x0,
        .din_ofs        = 0x080,
        .digcnt_ofs     = 0x040,
        .rev_ofs        = 0x100,
        .mask_ofs       = 0x110,
        .sysstatus_ofs  = 0x114,
+       .mode_ofs       = 0x44,
+       .length_ofs     = 0x48,
+       .major_mask     = 0x0700,
+       .major_shift    = 8,
+       .minor_mask     = 0x003f,
+       .minor_shift    = 0,
+};
+
+static struct omap_sham_algs_info omap_sham_algs_info_omap5[] = {
+       {
+               .algs_list      = algs_sha1_md5,
+               .size           = ARRAY_SIZE(algs_sha1_md5),
+       },
+       {
+               .algs_list      = algs_sha224_sha256,
+               .size           = ARRAY_SIZE(algs_sha224_sha256),
+       },
+       {
+               .algs_list      = algs_sha384_sha512,
+               .size           = ARRAY_SIZE(algs_sha384_sha512),
+       },
+};
+
+static const struct omap_sham_pdata omap_sham_pdata_omap5 = {
+       .algs_info      = omap_sham_algs_info_omap5,
+       .algs_info_size = ARRAY_SIZE(omap_sham_algs_info_omap5),
+       .flags          = BIT(FLAGS_AUTO_XOR),
+       .digest_size    = SHA512_DIGEST_SIZE,
+       .copy_hash      = omap_sham_copy_hash_omap4,
+       .write_ctrl     = omap_sham_write_ctrl_omap4,
+       .trigger        = omap_sham_trigger_omap4,
+       .poll_irq       = omap_sham_poll_irq_omap4,
+       .intr_hdlr      = omap_sham_irq_omap4,
+       .idigest_ofs    = 0x240,
+       .odigest_ofs    = 0x200,
+       .din_ofs        = 0x080,
+       .digcnt_ofs     = 0x280,
+       .rev_ofs        = 0x100,
+       .mask_ofs       = 0x110,
+       .sysstatus_ofs  = 0x114,
+       .mode_ofs       = 0x284,
+       .length_ofs     = 0x288,
        .major_mask     = 0x0700,
        .major_shift    = 8,
        .minor_mask     = 0x003f,
@@ -1568,6 +1789,10 @@ static const struct of_device_id omap_sham_of_match[] = {
                .compatible     = "ti,omap4-sham",
                .data           = &omap_sham_pdata_omap4,
        },
+       {
+               .compatible     = "ti,omap5-sham",
+               .data           = &omap_sham_pdata_omap5,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, omap_sham_of_match);
@@ -1667,7 +1892,7 @@ static int omap_sham_probe(struct platform_device *pdev)
        int err, i, j;
        u32 rev;
 
-       dd = kzalloc(sizeof(struct omap_sham_dev), GFP_KERNEL);
+       dd = devm_kzalloc(dev, sizeof(struct omap_sham_dev), GFP_KERNEL);
        if (dd == NULL) {
                dev_err(dev, "unable to alloc data struct.\n");
                err = -ENOMEM;
@@ -1684,20 +1909,21 @@ static int omap_sham_probe(struct platform_device *pdev)
        err = (dev->of_node) ? omap_sham_get_res_of(dd, dev, &res) :
                               omap_sham_get_res_pdev(dd, pdev, &res);
        if (err)
-               goto res_err;
+               goto data_err;
 
        dd->io_base = devm_ioremap_resource(dev, &res);
        if (IS_ERR(dd->io_base)) {
                err = PTR_ERR(dd->io_base);
-               goto res_err;
+               goto data_err;
        }
        dd->phys_base = res.start;
 
-       err = request_irq(dd->irq, dd->pdata->intr_hdlr, IRQF_TRIGGER_LOW,
-                         dev_name(dev), dd);
+       err = devm_request_irq(dev, dd->irq, dd->pdata->intr_hdlr,
+                              IRQF_TRIGGER_NONE, dev_name(dev), dd);
        if (err) {
-               dev_err(dev, "unable to request irq.\n");
-               goto res_err;
+               dev_err(dev, "unable to request irq %d, err = %d\n",
+                       dd->irq, err);
+               goto data_err;
        }
 
        dma_cap_zero(mask);
@@ -1706,10 +1932,8 @@ static int omap_sham_probe(struct platform_device *pdev)
        dd->dma_lch = dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
                                                       &dd->dma, dev, "rx");
        if (!dd->dma_lch) {
-               dev_err(dev, "unable to obtain RX DMA engine channel %u\n",
-                       dd->dma);
-               err = -ENXIO;
-               goto dma_err;
+               dd->polling_mode = 1;
+               dev_dbg(dev, "using polling mode instead of dma\n");
        }
 
        dd->flags |= dd->pdata->flags;
@@ -1747,11 +1971,6 @@ err_algs:
                                        &dd->pdata->algs_info[i].algs_list[j]);
        pm_runtime_disable(dev);
        dma_release_channel(dd->dma_lch);
-dma_err:
-       free_irq(dd->irq, dd);
-res_err:
-       kfree(dd);
-       dd = NULL;
 data_err:
        dev_err(dev, "initialization failed.\n");
 
@@ -1776,9 +1995,6 @@ static int omap_sham_remove(struct platform_device *pdev)
        tasklet_kill(&dd->done_task);
        pm_runtime_disable(&pdev->dev);
        dma_release_channel(dd->dma_lch);
-       free_irq(dd->irq, dd);
-       kfree(dd);
-       dd = NULL;
 
        return 0;
 }
index c3dc1c04a5df6f39966b3ca4a9c9874c001035ec..d7bb8bac36e973944334409760dc56c37eb02be1 100644 (file)
@@ -417,7 +417,7 @@ static void sahara_aes_done_task(unsigned long data)
        dev->req->base.complete(&dev->req->base, dev->error);
 }
 
-void sahara_watchdog(unsigned long data)
+static void sahara_watchdog(unsigned long data)
 {
        struct sahara_dev *dev = (struct sahara_dev *)data;
        unsigned int err = sahara_read(dev, SAHARA_REG_ERRSTATUS);
@@ -955,7 +955,7 @@ static int sahara_probe(struct platform_device *pdev)
        dev->hw_link[0] = dma_alloc_coherent(&pdev->dev,
                        SAHARA_MAX_HW_LINK * sizeof(struct sahara_hw_link),
                        &dev->hw_phys_link[0], GFP_KERNEL);
-       if (!dev->hw_link) {
+       if (!dev->hw_link[0]) {
                dev_err(&pdev->dev, "Could not allocate hw links\n");
                err = -ENOMEM;
                goto err_link;
index 85ea7525fa36242bda4cb21c37ce788981d3b502..2d58da972ae279f44b91f05dd472f6287c13f081 100644 (file)
@@ -275,7 +275,7 @@ static int aes_start_crypt(struct tegra_aes_dev *dd, u32 in_addr, u32 out_addr,
                        value = aes_readl(dd, TEGRA_AES_INTR_STATUS);
                        eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD;
                        icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD;
-               } while (eng_busy & (!icq_empty));
+               } while (eng_busy && !icq_empty);
                aes_writel(dd, cmdq[i], TEGRA_AES_ICMDQUE_WR);
        }
 
@@ -365,7 +365,7 @@ static int aes_set_key(struct tegra_aes_dev *dd)
                eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD;
                icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD;
                dma_busy = value & TEGRA_AES_DMA_BUSY_FIELD;
-       } while (eng_busy & (!icq_empty) & dma_busy);
+       } while (eng_busy && !icq_empty && dma_busy);
 
        /* settable command to get key into internal registers */
        value = CMD_SETTABLE << CMDQ_OPCODE_SHIFT |
@@ -379,7 +379,7 @@ static int aes_set_key(struct tegra_aes_dev *dd)
                value = aes_readl(dd, TEGRA_AES_INTR_STATUS);
                eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD;
                icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD;
-       } while (eng_busy & (!icq_empty));
+       } while (eng_busy && !icq_empty);
 
        return 0;
 }
index 33693d966b6a8238c5022586e58729cf43ac747c..1c73f4fbc2526027f96b2323b21b0c4c0c1e1b0f 100644 (file)
@@ -11,6 +11,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) "hashX hashX: " fmt
+
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -35,8 +37,6 @@
 
 #include "hash_alg.h"
 
-#define DEV_DBG_NAME "hashX hashX:"
-
 static int hash_mode;
 module_param(hash_mode, int, 0);
 MODULE_PARM_DESC(hash_mode, "CPU or DMA mode. CPU = 0 (default), DMA = 1");
@@ -44,13 +44,13 @@ MODULE_PARM_DESC(hash_mode, "CPU or DMA mode. CPU = 0 (default), DMA = 1");
 /**
  * Pre-calculated empty message digests.
  */
-static u8 zero_message_hash_sha1[SHA1_DIGEST_SIZE] = {
+static const u8 zero_message_hash_sha1[SHA1_DIGEST_SIZE] = {
        0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d,
        0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90,
        0xaf, 0xd8, 0x07, 0x09
 };
 
-static u8 zero_message_hash_sha256[SHA256_DIGEST_SIZE] = {
+static const u8 zero_message_hash_sha256[SHA256_DIGEST_SIZE] = {
        0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
        0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
        0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
@@ -58,14 +58,14 @@ static u8 zero_message_hash_sha256[SHA256_DIGEST_SIZE] = {
 };
 
 /* HMAC-SHA1, no key */
-static u8 zero_message_hmac_sha1[SHA1_DIGEST_SIZE] = {
+static const u8 zero_message_hmac_sha1[SHA1_DIGEST_SIZE] = {
        0xfb, 0xdb, 0x1d, 0x1b, 0x18, 0xaa, 0x6c, 0x08,
        0x32, 0x4b, 0x7d, 0x64, 0xb7, 0x1f, 0xb7, 0x63,
        0x70, 0x69, 0x0e, 0x1d
 };
 
 /* HMAC-SHA256, no key */
-static u8 zero_message_hmac_sha256[SHA256_DIGEST_SIZE] = {
+static const u8 zero_message_hmac_sha256[SHA256_DIGEST_SIZE] = {
        0xb6, 0x13, 0x67, 0x9a, 0x08, 0x14, 0xd9, 0xec,
        0x77, 0x2f, 0x95, 0xd7, 0x78, 0xc3, 0x5f, 0xc5,
        0xff, 0x16, 0x97, 0xc4, 0x93, 0x71, 0x56, 0x53,
@@ -97,7 +97,7 @@ static struct hash_driver_data        driver_data;
  *
  */
 static void hash_messagepad(struct hash_device_data *device_data,
-               const u32 *message, u8 index_bytes);
+                           const u32 *message, u8 index_bytes);
 
 /**
  * release_hash_device - Releases a previously allocated hash device.
@@ -119,7 +119,7 @@ static void release_hash_device(struct hash_device_data *device_data)
 }
 
 static void hash_dma_setup_channel(struct hash_device_data *device_data,
-                               struct device *dev)
+                                  struct device *dev)
 {
        struct hash_platform_data *platform_data = dev->platform_data;
        struct dma_slave_config conf = {
@@ -127,7 +127,7 @@ static void hash_dma_setup_channel(struct hash_device_data *device_data,
                .dst_addr = device_data->phybase + HASH_DMA_FIFO,
                .dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,
                .dst_maxburst = 16,
-        };
+       };
 
        dma_cap_zero(device_data->dma.mask);
        dma_cap_set(DMA_SLAVE, device_data->dma.mask);
@@ -135,8 +135,8 @@ static void hash_dma_setup_channel(struct hash_device_data *device_data,
        device_data->dma.cfg_mem2hash = platform_data->mem_to_engine;
        device_data->dma.chan_mem2hash =
                dma_request_channel(device_data->dma.mask,
-                               platform_data->dma_filter,
-                               device_data->dma.cfg_mem2hash);
+                                   platform_data->dma_filter,
+                                   device_data->dma.cfg_mem2hash);
 
        dmaengine_slave_config(device_data->dma.chan_mem2hash, &conf);
 
@@ -145,21 +145,21 @@ static void hash_dma_setup_channel(struct hash_device_data *device_data,
 
 static void hash_dma_callback(void *data)
 {
-       struct hash_ctx *ctx = (struct hash_ctx *) data;
+       struct hash_ctx *ctx = data;
 
        complete(&ctx->device->dma.complete);
 }
 
 static int hash_set_dma_transfer(struct hash_ctx *ctx, struct scatterlist *sg,
-               int len, enum dma_data_direction direction)
+                                int len, enum dma_data_direction direction)
 {
        struct dma_async_tx_descriptor *desc = NULL;
        struct dma_chan *channel = NULL;
        dma_cookie_t cookie;
 
        if (direction != DMA_TO_DEVICE) {
-               dev_err(ctx->device->dev, "[%s] Invalid DMA direction",
-                               __func__);
+               dev_err(ctx->device->dev, "%s: Invalid DMA direction\n",
+                       __func__);
                return -EFAULT;
        }
 
@@ -172,20 +172,19 @@ static int hash_set_dma_transfer(struct hash_ctx *ctx, struct scatterlist *sg,
                        direction);
 
        if (!ctx->device->dma.sg_len) {
-               dev_err(ctx->device->dev,
-                               "[%s]: Could not map the sg list (TO_DEVICE)",
-                               __func__);
+               dev_err(ctx->device->dev, "%s: Could not map the sg list (TO_DEVICE)\n",
+                       __func__);
                return -EFAULT;
        }
 
-       dev_dbg(ctx->device->dev, "[%s]: Setting up DMA for buffer "
-                       "(TO_DEVICE)", __func__);
+       dev_dbg(ctx->device->dev, "%s: Setting up DMA for buffer (TO_DEVICE)\n",
+               __func__);
        desc = dmaengine_prep_slave_sg(channel,
                        ctx->device->dma.sg, ctx->device->dma.sg_len,
                        direction, DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
        if (!desc) {
                dev_err(ctx->device->dev,
-                       "[%s]: device_prep_slave_sg() failed!", __func__);
+                       "%s: device_prep_slave_sg() failed!\n", __func__);
                return -EFAULT;
        }
 
@@ -205,17 +204,16 @@ static void hash_dma_done(struct hash_ctx *ctx)
        chan = ctx->device->dma.chan_mem2hash;
        dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
        dma_unmap_sg(chan->device->dev, ctx->device->dma.sg,
-                       ctx->device->dma.sg_len, DMA_TO_DEVICE);
-
+                    ctx->device->dma.sg_len, DMA_TO_DEVICE);
 }
 
 static int hash_dma_write(struct hash_ctx *ctx,
-               struct scatterlist *sg, int len)
+                         struct scatterlist *sg, int len)
 {
        int error = hash_set_dma_transfer(ctx, sg, len, DMA_TO_DEVICE);
        if (error) {
-               dev_dbg(ctx->device->dev, "[%s]: hash_set_dma_transfer() "
-                       "failed", __func__);
+               dev_dbg(ctx->device->dev,
+                       "%s: hash_set_dma_transfer() failed\n", __func__);
                return error;
        }
 
@@ -245,19 +243,18 @@ static int get_empty_message_digest(
        if (HASH_OPER_MODE_HASH == ctx->config.oper_mode) {
                if (HASH_ALGO_SHA1 == ctx->config.algorithm) {
                        memcpy(zero_hash, &zero_message_hash_sha1[0],
-                                       SHA1_DIGEST_SIZE);
+                              SHA1_DIGEST_SIZE);
                        *zero_hash_size = SHA1_DIGEST_SIZE;
                        *zero_digest = true;
                } else if (HASH_ALGO_SHA256 ==
                                ctx->config.algorithm) {
                        memcpy(zero_hash, &zero_message_hash_sha256[0],
-                                       SHA256_DIGEST_SIZE);
+                              SHA256_DIGEST_SIZE);
                        *zero_hash_size = SHA256_DIGEST_SIZE;
                        *zero_digest = true;
                } else {
-                       dev_err(device_data->dev, "[%s] "
-                                       "Incorrect algorithm!"
-                                       , __func__);
+                       dev_err(device_data->dev, "%s: Incorrect algorithm!\n",
+                               __func__);
                        ret = -EINVAL;
                        goto out;
                }
@@ -265,25 +262,24 @@ static int get_empty_message_digest(
                if (!ctx->keylen) {
                        if (HASH_ALGO_SHA1 == ctx->config.algorithm) {
                                memcpy(zero_hash, &zero_message_hmac_sha1[0],
-                                               SHA1_DIGEST_SIZE);
+                                      SHA1_DIGEST_SIZE);
                                *zero_hash_size = SHA1_DIGEST_SIZE;
                                *zero_digest = true;
                        } else if (HASH_ALGO_SHA256 == ctx->config.algorithm) {
                                memcpy(zero_hash, &zero_message_hmac_sha256[0],
-                                               SHA256_DIGEST_SIZE);
+                                      SHA256_DIGEST_SIZE);
                                *zero_hash_size = SHA256_DIGEST_SIZE;
                                *zero_digest = true;
                        } else {
-                               dev_err(device_data->dev, "[%s] "
-                                               "Incorrect algorithm!"
-                                               , __func__);
+                               dev_err(device_data->dev, "%s: Incorrect algorithm!\n",
+                                       __func__);
                                ret = -EINVAL;
                                goto out;
                        }
                } else {
-                       dev_dbg(device_data->dev, "[%s] Continue hash "
-                                       "calculation, since hmac key available",
-                                       __func__);
+                       dev_dbg(device_data->dev,
+                               "%s: Continue hash calculation, since hmac key available\n",
+                               __func__);
                }
        }
 out:
@@ -299,9 +295,8 @@ out:
  * This function request for disabling power (regulator) and clock,
  * and could also save current hw state.
  */
-static int hash_disable_power(
-               struct hash_device_data *device_data,
-               bool                    save_device_state)
+static int hash_disable_power(struct hash_device_data *device_data,
+                             bool save_device_state)
 {
        int ret = 0;
        struct device *dev = device_data->dev;
@@ -319,7 +314,7 @@ static int hash_disable_power(
        clk_disable(device_data->clk);
        ret = regulator_disable(device_data->regulator);
        if (ret)
-               dev_err(dev, "[%s] regulator_disable() failed!", __func__);
+               dev_err(dev, "%s: regulator_disable() failed!\n", __func__);
 
        device_data->power_state = false;
 
@@ -337,9 +332,8 @@ out:
  * This function request for enabling power (regulator) and clock,
  * and could also restore a previously saved hw state.
  */
-static int hash_enable_power(
-               struct hash_device_data *device_data,
-               bool                    restore_device_state)
+static int hash_enable_power(struct hash_device_data *device_data,
+                            bool restore_device_state)
 {
        int ret = 0;
        struct device *dev = device_data->dev;
@@ -348,14 +342,13 @@ static int hash_enable_power(
        if (!device_data->power_state) {
                ret = regulator_enable(device_data->regulator);
                if (ret) {
-                       dev_err(dev, "[%s]: regulator_enable() failed!",
-                                       __func__);
+                       dev_err(dev, "%s: regulator_enable() failed!\n",
+                               __func__);
                        goto out;
                }
                ret = clk_enable(device_data->clk);
                if (ret) {
-                       dev_err(dev, "[%s]: clk_enable() failed!",
-                                       __func__);
+                       dev_err(dev, "%s: clk_enable() failed!\n", __func__);
                        ret = regulator_disable(
                                        device_data->regulator);
                        goto out;
@@ -366,8 +359,7 @@ static int hash_enable_power(
        if (device_data->restore_dev_state) {
                if (restore_device_state) {
                        device_data->restore_dev_state = false;
-                       hash_resume_state(device_data,
-                               &device_data->state);
+                       hash_resume_state(device_data, &device_data->state);
                }
        }
 out:
@@ -447,7 +439,7 @@ static int hash_get_device_data(struct hash_ctx *ctx,
  * spec or due to a bug in the hw.
  */
 static void hash_hw_write_key(struct hash_device_data *device_data,
-               const u8 *key, unsigned int keylen)
+                             const u8 *key, unsigned int keylen)
 {
        u32 word = 0;
        int nwords = 1;
@@ -491,14 +483,14 @@ static void hash_hw_write_key(struct hash_device_data *device_data,
  * calculation.
  */
 static int init_hash_hw(struct hash_device_data *device_data,
-               struct hash_ctx *ctx)
+                       struct hash_ctx *ctx)
 {
        int ret = 0;
 
        ret = hash_setconfiguration(device_data, &ctx->config);
        if (ret) {
-               dev_err(device_data->dev, "[%s] hash_setconfiguration() "
-                               "failed!", __func__);
+               dev_err(device_data->dev, "%s: hash_setconfiguration() failed!\n",
+                       __func__);
                return ret;
        }
 
@@ -528,9 +520,8 @@ static int hash_get_nents(struct scatterlist *sg, int size, bool *aligned)
                size -= sg->length;
 
                /* hash_set_dma_transfer will align last nent */
-               if ((aligned && !IS_ALIGNED(sg->offset, HASH_DMA_ALIGN_SIZE))
-                       || (!IS_ALIGNED(sg->length, HASH_DMA_ALIGN_SIZE) &&
-                               size > 0))
+               if ((aligned && !IS_ALIGNED(sg->offset, HASH_DMA_ALIGN_SIZE)) ||
+                   (!IS_ALIGNED(sg->length, HASH_DMA_ALIGN_SIZE) && size > 0))
                        aligned_data = false;
 
                sg = sg_next(sg);
@@ -585,21 +576,17 @@ static int hash_init(struct ahash_request *req)
                if (req->nbytes < HASH_DMA_ALIGN_SIZE) {
                        req_ctx->dma_mode = false; /* Don't use DMA */
 
-                       pr_debug(DEV_DBG_NAME " [%s] DMA mode, but direct "
-                                       "to CPU mode for data size < %d",
-                                       __func__, HASH_DMA_ALIGN_SIZE);
+                       pr_debug("%s: DMA mode, but direct to CPU mode for data size < %d\n",
+                                __func__, HASH_DMA_ALIGN_SIZE);
                } else {
                        if (req->nbytes >= HASH_DMA_PERFORMANCE_MIN_SIZE &&
-                                       hash_dma_valid_data(req->src,
-                                               req->nbytes)) {
+                           hash_dma_valid_data(req->src, req->nbytes)) {
                                req_ctx->dma_mode = true;
                        } else {
                                req_ctx->dma_mode = false;
-                               pr_debug(DEV_DBG_NAME " [%s] DMA mode, but use"
-                                               " CPU mode for datalength < %d"
-                                               " or non-aligned data, except "
-                                               "in last nent", __func__,
-                                               HASH_DMA_PERFORMANCE_MIN_SIZE);
+                               pr_debug("%s: DMA mode, but use CPU mode for datalength < %d or non-aligned data, except in last nent\n",
+                                        __func__,
+                                        HASH_DMA_PERFORMANCE_MIN_SIZE);
                        }
                }
        }
@@ -614,9 +601,8 @@ static int hash_init(struct ahash_request *req)
  *                     the HASH hardware.
  *
  */
-static void hash_processblock(
-               struct hash_device_data *device_data,
-               const u32 *message, int length)
+static void hash_processblock(struct hash_device_data *device_data,
+                             const u32 *message, int length)
 {
        int len = length / HASH_BYTES_PER_WORD;
        /*
@@ -641,7 +627,7 @@ static void hash_processblock(
  *
  */
 static void hash_messagepad(struct hash_device_data *device_data,
-               const u32 *message, u8 index_bytes)
+                           const u32 *message, u8 index_bytes)
 {
        int nwords = 1;
 
@@ -666,15 +652,13 @@ static void hash_messagepad(struct hash_device_data *device_data,
 
        /* num_of_bytes == 0 => NBLW <- 0 (32 bits valid in DATAIN) */
        HASH_SET_NBLW(index_bytes * 8);
-       dev_dbg(device_data->dev, "[%s] DIN=0x%08x NBLW=%d", __func__,
-                       readl_relaxed(&device_data->base->din),
-                       (int)(readl_relaxed(&device_data->base->str) &
-                               HASH_STR_NBLW_MASK));
+       dev_dbg(device_data->dev, "%s: DIN=0x%08x NBLW=%lu\n",
+               __func__, readl_relaxed(&device_data->base->din),
+               readl_relaxed(&device_data->base->str) & HASH_STR_NBLW_MASK);
        HASH_SET_DCAL;
-       dev_dbg(device_data->dev, "[%s] after dcal -> DIN=0x%08x NBLW=%d",
-                       __func__, readl_relaxed(&device_data->base->din),
-                       (int)(readl_relaxed(&device_data->base->str) &
-                               HASH_STR_NBLW_MASK));
+       dev_dbg(device_data->dev, "%s: after dcal -> DIN=0x%08x NBLW=%lu\n",
+               __func__, readl_relaxed(&device_data->base->din),
+               readl_relaxed(&device_data->base->str) & HASH_STR_NBLW_MASK);
 
        while (readl(&device_data->base->str) & HASH_STR_DCAL_MASK)
                cpu_relax();
@@ -704,7 +688,7 @@ static void hash_incrementlength(struct hash_req_ctx *ctx, u32 incr)
  * @config:            Pointer to a configuration structure.
  */
 int hash_setconfiguration(struct hash_device_data *device_data,
-               struct hash_config *config)
+                         struct hash_config *config)
 {
        int ret = 0;
 
@@ -731,8 +715,8 @@ int hash_setconfiguration(struct hash_device_data *device_data,
                break;
 
        default:
-               dev_err(device_data->dev, "[%s] Incorrect algorithm.",
-                               __func__);
+               dev_err(device_data->dev, "%s: Incorrect algorithm\n",
+                       __func__);
                return -EPERM;
        }
 
@@ -744,23 +728,22 @@ int hash_setconfiguration(struct hash_device_data *device_data,
                HASH_CLEAR_BITS(&device_data->base->cr,
                                HASH_CR_MODE_MASK);
        else if (HASH_OPER_MODE_HMAC == config->oper_mode) {
-               HASH_SET_BITS(&device_data->base->cr,
-                               HASH_CR_MODE_MASK);
+               HASH_SET_BITS(&device_data->base->cr, HASH_CR_MODE_MASK);
                if (device_data->current_ctx->keylen > HASH_BLOCK_SIZE) {
                        /* Truncate key to blocksize */
-                       dev_dbg(device_data->dev, "[%s] LKEY set", __func__);
+                       dev_dbg(device_data->dev, "%s: LKEY set\n", __func__);
                        HASH_SET_BITS(&device_data->base->cr,
-                                       HASH_CR_LKEY_MASK);
+                                     HASH_CR_LKEY_MASK);
                } else {
-                       dev_dbg(device_data->dev, "[%s] LKEY cleared",
-                                       __func__);
+                       dev_dbg(device_data->dev, "%s: LKEY cleared\n",
+                               __func__);
                        HASH_CLEAR_BITS(&device_data->base->cr,
                                        HASH_CR_LKEY_MASK);
                }
        } else {        /* Wrong hash mode */
                ret = -EPERM;
-               dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
-                               __func__);
+               dev_err(device_data->dev, "%s: HASH_INVALID_PARAMETER!\n",
+                       __func__);
        }
        return ret;
 }
@@ -793,8 +776,9 @@ void hash_begin(struct hash_device_data *device_data, struct hash_ctx *ctx)
 }
 
 static int hash_process_data(struct hash_device_data *device_data,
-               struct hash_ctx *ctx, struct hash_req_ctx *req_ctx,
-               int msg_length, u8 *data_buffer, u8 *buffer, u8 *index)
+                            struct hash_ctx *ctx, struct hash_req_ctx *req_ctx,
+                            int msg_length, u8 *data_buffer, u8 *buffer,
+                            u8 *index)
 {
        int ret = 0;
        u32 count;
@@ -809,24 +793,23 @@ static int hash_process_data(struct hash_device_data *device_data,
                        msg_length = 0;
                } else {
                        if (req_ctx->updated) {
-
                                ret = hash_resume_state(device_data,
                                                &device_data->state);
                                memmove(req_ctx->state.buffer,
-                                               device_data->state.buffer,
-                                               HASH_BLOCK_SIZE / sizeof(u32));
+                                       device_data->state.buffer,
+                                       HASH_BLOCK_SIZE / sizeof(u32));
                                if (ret) {
-                                       dev_err(device_data->dev, "[%s] "
-                                                       "hash_resume_state()"
-                                                       " failed!", __func__);
+                                       dev_err(device_data->dev,
+                                               "%s: hash_resume_state() failed!\n",
+                                               __func__);
                                        goto out;
                                }
                        } else {
                                ret = init_hash_hw(device_data, ctx);
                                if (ret) {
-                                       dev_err(device_data->dev, "[%s] "
-                                                       "init_hash_hw()"
-                                                       " failed!", __func__);
+                                       dev_err(device_data->dev,
+                                               "%s: init_hash_hw() failed!\n",
+                                               __func__);
                                        goto out;
                                }
                                req_ctx->updated = 1;
@@ -838,22 +821,21 @@ static int hash_process_data(struct hash_device_data *device_data,
                         * HW peripheral, otherwise we first copy data
                         * to a local buffer
                         */
-                       if ((0 == (((u32)data_buffer) % 4))
-                                       && (0 == *index))
+                       if ((0 == (((u32)data_buffer) % 4)) &&
+                           (0 == *index))
                                hash_processblock(device_data,
-                                               (const u32 *)
-                                               data_buffer, HASH_BLOCK_SIZE);
+                                                 (const u32 *)data_buffer,
+                                                 HASH_BLOCK_SIZE);
                        else {
-                               for (count = 0; count <
-                                               (u32)(HASH_BLOCK_SIZE -
-                                                       *index);
-                                               count++) {
+                               for (count = 0;
+                                    count < (u32)(HASH_BLOCK_SIZE - *index);
+                                    count++) {
                                        buffer[*index + count] =
                                                *(data_buffer + count);
                                }
                                hash_processblock(device_data,
-                                               (const u32 *)buffer,
-                                               HASH_BLOCK_SIZE);
+                                                 (const u32 *)buffer,
+                                                 HASH_BLOCK_SIZE);
                        }
                        hash_incrementlength(req_ctx, HASH_BLOCK_SIZE);
                        data_buffer += (HASH_BLOCK_SIZE - *index);
@@ -865,12 +847,11 @@ static int hash_process_data(struct hash_device_data *device_data,
                                        &device_data->state);
 
                        memmove(device_data->state.buffer,
-                                       req_ctx->state.buffer,
-                                       HASH_BLOCK_SIZE / sizeof(u32));
+                               req_ctx->state.buffer,
+                               HASH_BLOCK_SIZE / sizeof(u32));
                        if (ret) {
-                               dev_err(device_data->dev, "[%s] "
-                                               "hash_save_state()"
-                                               " failed!", __func__);
+                               dev_err(device_data->dev, "%s: hash_save_state() failed!\n",
+                                       __func__);
                                goto out;
                        }
                }
@@ -898,25 +879,24 @@ static int hash_dma_final(struct ahash_request *req)
        if (ret)
                return ret;
 
-       dev_dbg(device_data->dev, "[%s] (ctx=0x%x)!", __func__, (u32) ctx);
+       dev_dbg(device_data->dev, "%s: (ctx=0x%x)!\n", __func__, (u32) ctx);
 
        if (req_ctx->updated) {
                ret = hash_resume_state(device_data, &device_data->state);
 
                if (ret) {
-                       dev_err(device_data->dev, "[%s] hash_resume_state() "
-                                       "failed!", __func__);
+                       dev_err(device_data->dev, "%s: hash_resume_state() failed!\n",
+                               __func__);
                        goto out;
                }
-
        }
 
        if (!req_ctx->updated) {
                ret = hash_setconfiguration(device_data, &ctx->config);
                if (ret) {
-                       dev_err(device_data->dev, "[%s] "
-                                       "hash_setconfiguration() failed!",
-                                       __func__);
+                       dev_err(device_data->dev,
+                               "%s: hash_setconfiguration() failed!\n",
+                               __func__);
                        goto out;
                }
 
@@ -926,9 +906,9 @@ static int hash_dma_final(struct ahash_request *req)
                                        HASH_CR_DMAE_MASK);
                } else {
                        HASH_SET_BITS(&device_data->base->cr,
-                                       HASH_CR_DMAE_MASK);
+                                     HASH_CR_DMAE_MASK);
                        HASH_SET_BITS(&device_data->base->cr,
-                                       HASH_CR_PRIVN_MASK);
+                                     HASH_CR_PRIVN_MASK);
                }
 
                HASH_INITIALIZE;
@@ -944,16 +924,16 @@ static int hash_dma_final(struct ahash_request *req)
        /* Store the nents in the dma struct. */
        ctx->device->dma.nents = hash_get_nents(req->src, req->nbytes, NULL);
        if (!ctx->device->dma.nents) {
-               dev_err(device_data->dev, "[%s] "
-                               "ctx->device->dma.nents = 0", __func__);
+               dev_err(device_data->dev, "%s: ctx->device->dma.nents = 0\n",
+                       __func__);
                ret = ctx->device->dma.nents;
                goto out;
        }
 
        bytes_written = hash_dma_write(ctx, req->src, req->nbytes);
        if (bytes_written != req->nbytes) {
-               dev_err(device_data->dev, "[%s] "
-                               "hash_dma_write() failed!", __func__);
+               dev_err(device_data->dev, "%s: hash_dma_write() failed!\n",
+                       __func__);
                ret = bytes_written;
                goto out;
        }
@@ -968,8 +948,8 @@ static int hash_dma_final(struct ahash_request *req)
                unsigned int keylen = ctx->keylen;
                u8 *key = ctx->key;
 
-               dev_dbg(device_data->dev, "[%s] keylen: %d", __func__,
-                               ctx->keylen);
+               dev_dbg(device_data->dev, "%s: keylen: %d\n",
+                       __func__, ctx->keylen);
                hash_hw_write_key(device_data, key, keylen);
        }
 
@@ -1004,14 +984,14 @@ static int hash_hw_final(struct ahash_request *req)
        if (ret)
                return ret;
 
-       dev_dbg(device_data->dev, "[%s] (ctx=0x%x)!", __func__, (u32) ctx);
+       dev_dbg(device_data->dev, "%s: (ctx=0x%x)!\n", __func__, (u32) ctx);
 
        if (req_ctx->updated) {
                ret = hash_resume_state(device_data, &device_data->state);
 
                if (ret) {
-                       dev_err(device_data->dev, "[%s] hash_resume_state() "
-                                       "failed!", __func__);
+                       dev_err(device_data->dev,
+                               "%s: hash_resume_state() failed!\n", __func__);
                        goto out;
                }
        } else if (req->nbytes == 0 && ctx->keylen == 0) {
@@ -1025,31 +1005,33 @@ static int hash_hw_final(struct ahash_request *req)
                ret = get_empty_message_digest(device_data, &zero_hash[0],
                                &zero_hash_size, &zero_digest);
                if (!ret && likely(zero_hash_size == ctx->digestsize) &&
-                               zero_digest) {
+                   zero_digest) {
                        memcpy(req->result, &zero_hash[0], ctx->digestsize);
                        goto out;
                } else if (!ret && !zero_digest) {
-                       dev_dbg(device_data->dev, "[%s] HMAC zero msg with "
-                                       "key, continue...", __func__);
+                       dev_dbg(device_data->dev,
+                               "%s: HMAC zero msg with key, continue...\n",
+                               __func__);
                } else {
-                       dev_err(device_data->dev, "[%s] ret=%d, or wrong "
-                                       "digest size? %s", __func__, ret,
-                                       (zero_hash_size == ctx->digestsize) ?
-                                       "true" : "false");
+                       dev_err(device_data->dev,
+                               "%s: ret=%d, or wrong digest size? %s\n",
+                               __func__, ret,
+                               zero_hash_size == ctx->digestsize ?
+                               "true" : "false");
                        /* Return error */
                        goto out;
                }
        } else if (req->nbytes == 0 && ctx->keylen > 0) {
-               dev_err(device_data->dev, "[%s] Empty message with "
-                               "keylength > 0, NOT supported.", __func__);
+               dev_err(device_data->dev, "%s: Empty message with keylength > 0, NOT supported\n",
+                       __func__);
                goto out;
        }
 
        if (!req_ctx->updated) {
                ret = init_hash_hw(device_data, ctx);
                if (ret) {
-                       dev_err(device_data->dev, "[%s] init_hash_hw() "
-                                       "failed!", __func__);
+                       dev_err(device_data->dev,
+                               "%s: init_hash_hw() failed!\n", __func__);
                        goto out;
                }
        }
@@ -1067,8 +1049,8 @@ static int hash_hw_final(struct ahash_request *req)
                unsigned int keylen = ctx->keylen;
                u8 *key = ctx->key;
 
-               dev_dbg(device_data->dev, "[%s] keylen: %d", __func__,
-                               ctx->keylen);
+               dev_dbg(device_data->dev, "%s: keylen: %d\n",
+                       __func__, ctx->keylen);
                hash_hw_write_key(device_data, key, keylen);
        }
 
@@ -1115,10 +1097,8 @@ int hash_hw_update(struct ahash_request *req)
        /* Check if ctx->state.length + msg_length
           overflows */
        if (msg_length > (req_ctx->state.length.low_word + msg_length) &&
-                       HASH_HIGH_WORD_MAX_VAL ==
-                       req_ctx->state.length.high_word) {
-               pr_err(DEV_DBG_NAME " [%s] HASH_MSG_LENGTH_OVERFLOW!",
-                               __func__);
+           HASH_HIGH_WORD_MAX_VAL == req_ctx->state.length.high_word) {
+               pr_err("%s: HASH_MSG_LENGTH_OVERFLOW!\n", __func__);
                return -EPERM;
        }
 
@@ -1133,8 +1113,8 @@ int hash_hw_update(struct ahash_request *req)
                                data_buffer, buffer, &index);
 
                if (ret) {
-                       dev_err(device_data->dev, "[%s] hash_internal_hw_"
-                                       "update() failed!", __func__);
+                       dev_err(device_data->dev, "%s: hash_internal_hw_update() failed!\n",
+                               __func__);
                        goto out;
                }
 
@@ -1142,9 +1122,8 @@ int hash_hw_update(struct ahash_request *req)
        }
 
        req_ctx->state.index = index;
-       dev_dbg(device_data->dev, "[%s] indata length=%d, bin=%d))",
-                       __func__, req_ctx->state.index,
-                       req_ctx->state.bit_index);
+       dev_dbg(device_data->dev, "%s: indata length=%d, bin=%d\n",
+               __func__, req_ctx->state.index, req_ctx->state.bit_index);
 
 out:
        release_hash_device(device_data);
@@ -1158,23 +1137,23 @@ out:
  * @device_state:      The state to be restored in the hash hardware
  */
 int hash_resume_state(struct hash_device_data *device_data,
-               const struct hash_state *device_state)
+                     const struct hash_state *device_state)
 {
        u32 temp_cr;
        s32 count;
        int hash_mode = HASH_OPER_MODE_HASH;
 
        if (NULL == device_state) {
-               dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
-                               __func__);
+               dev_err(device_data->dev, "%s: HASH_INVALID_PARAMETER!\n",
+                       __func__);
                return -EPERM;
        }
 
        /* Check correctness of index and length members */
-       if (device_state->index > HASH_BLOCK_SIZE
-           || (device_state->length.low_word % HASH_BLOCK_SIZE) != 0) {
-               dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
-                               __func__);
+       if (device_state->index > HASH_BLOCK_SIZE ||
+           (device_state->length.low_word % HASH_BLOCK_SIZE) != 0) {
+               dev_err(device_data->dev, "%s: HASH_INVALID_PARAMETER!\n",
+                       __func__);
                return -EPERM;
        }
 
@@ -1198,7 +1177,7 @@ int hash_resume_state(struct hash_device_data *device_data,
                        break;
 
                writel_relaxed(device_state->csr[count],
-                               &device_data->base->csrx[count]);
+                              &device_data->base->csrx[count]);
        }
 
        writel_relaxed(device_state->csfull, &device_data->base->csfull);
@@ -1216,15 +1195,15 @@ int hash_resume_state(struct hash_device_data *device_data,
  * @device_state:      The strucure where the hardware state should be saved.
  */
 int hash_save_state(struct hash_device_data *device_data,
-               struct hash_state *device_state)
+                   struct hash_state *device_state)
 {
        u32 temp_cr;
        u32 count;
        int hash_mode = HASH_OPER_MODE_HASH;
 
        if (NULL == device_state) {
-               dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
-                               __func__);
+               dev_err(device_data->dev, "%s: HASH_INVALID_PARAMETER!\n",
+                       __func__);
                return -ENOTSUPP;
        }
 
@@ -1270,20 +1249,18 @@ int hash_save_state(struct hash_device_data *device_data,
 int hash_check_hw(struct hash_device_data *device_data)
 {
        /* Checking Peripheral Ids  */
-       if (HASH_P_ID0 == readl_relaxed(&device_data->base->periphid0)
-               && HASH_P_ID1 == readl_relaxed(&device_data->base->periphid1)
-               && HASH_P_ID2 == readl_relaxed(&device_data->base->periphid2)
-               && HASH_P_ID3 == readl_relaxed(&device_data->base->periphid3)
-               && HASH_CELL_ID0 == readl_relaxed(&device_data->base->cellid0)
-               && HASH_CELL_ID1 == readl_relaxed(&device_data->base->cellid1)
-               && HASH_CELL_ID2 == readl_relaxed(&device_data->base->cellid2)
-               && HASH_CELL_ID3 == readl_relaxed(&device_data->base->cellid3)
-          ) {
+       if (HASH_P_ID0 == readl_relaxed(&device_data->base->periphid0) &&
+           HASH_P_ID1 == readl_relaxed(&device_data->base->periphid1) &&
+           HASH_P_ID2 == readl_relaxed(&device_data->base->periphid2) &&
+           HASH_P_ID3 == readl_relaxed(&device_data->base->periphid3) &&
+           HASH_CELL_ID0 == readl_relaxed(&device_data->base->cellid0) &&
+           HASH_CELL_ID1 == readl_relaxed(&device_data->base->cellid1) &&
+           HASH_CELL_ID2 == readl_relaxed(&device_data->base->cellid2) &&
+           HASH_CELL_ID3 == readl_relaxed(&device_data->base->cellid3)) {
                return 0;
        }
 
-       dev_err(device_data->dev, "[%s] HASH_UNSUPPORTED_HW!",
-                       __func__);
+       dev_err(device_data->dev, "%s: HASH_UNSUPPORTED_HW!\n", __func__);
        return -ENOTSUPP;
 }
 
@@ -1294,14 +1271,14 @@ int hash_check_hw(struct hash_device_data *device_data)
  * @algorithm:         The algorithm in use.
  */
 void hash_get_digest(struct hash_device_data *device_data,
-               u8 *digest, int algorithm)
+                    u8 *digest, int algorithm)
 {
        u32 temp_hx_val, count;
        int loop_ctr;
 
        if (algorithm != HASH_ALGO_SHA1 && algorithm != HASH_ALGO_SHA256) {
-               dev_err(device_data->dev, "[%s] Incorrect algorithm %d",
-                               __func__, algorithm);
+               dev_err(device_data->dev, "%s: Incorrect algorithm %d\n",
+                       __func__, algorithm);
                return;
        }
 
@@ -1310,8 +1287,8 @@ void hash_get_digest(struct hash_device_data *device_data,
        else
                loop_ctr = SHA256_DIGEST_SIZE / sizeof(u32);
 
-       dev_dbg(device_data->dev, "[%s] digest array:(0x%x)",
-                       __func__, (u32) digest);
+       dev_dbg(device_data->dev, "%s: digest array:(0x%x)\n",
+               __func__, (u32) digest);
 
        /* Copy result into digest array */
        for (count = 0; count < loop_ctr; count++) {
@@ -1337,8 +1314,7 @@ static int ahash_update(struct ahash_request *req)
        /* Skip update for DMA, all data will be passed to DMA in final */
 
        if (ret) {
-               pr_err(DEV_DBG_NAME " [%s] hash_hw_update() failed!",
-                               __func__);
+               pr_err("%s: hash_hw_update() failed!\n", __func__);
        }
 
        return ret;
@@ -1353,7 +1329,7 @@ static int ahash_final(struct ahash_request *req)
        int ret = 0;
        struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
 
-       pr_debug(DEV_DBG_NAME " [%s] data size: %d", __func__, req->nbytes);
+       pr_debug("%s: data size: %d\n", __func__, req->nbytes);
 
        if ((hash_mode == HASH_MODE_DMA) && req_ctx->dma_mode)
                ret = hash_dma_final(req);
@@ -1361,15 +1337,14 @@ static int ahash_final(struct ahash_request *req)
                ret = hash_hw_final(req);
 
        if (ret) {
-               pr_err(DEV_DBG_NAME " [%s] hash_hw/dma_final() failed",
-                               __func__);
+               pr_err("%s: hash_hw/dma_final() failed\n", __func__);
        }
 
        return ret;
 }
 
 static int hash_setkey(struct crypto_ahash *tfm,
-               const u8 *key, unsigned int keylen, int alg)
+                      const u8 *key, unsigned int keylen, int alg)
 {
        int ret = 0;
        struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
@@ -1379,8 +1354,8 @@ static int hash_setkey(struct crypto_ahash *tfm,
         */
        ctx->key = kmemdup(key, keylen, GFP_KERNEL);
        if (!ctx->key) {
-               pr_err(DEV_DBG_NAME " [%s] Failed to allocate ctx->key "
-                      "for %d\n", __func__, alg);
+               pr_err("%s: Failed to allocate ctx->key for %d\n",
+                      __func__, alg);
                return -ENOMEM;
        }
        ctx->keylen = keylen;
@@ -1501,13 +1476,13 @@ out:
 }
 
 static int hmac_sha1_setkey(struct crypto_ahash *tfm,
-               const u8 *key, unsigned int keylen)
+                           const u8 *key, unsigned int keylen)
 {
        return hash_setkey(tfm, key, keylen, HASH_ALGO_SHA1);
 }
 
 static int hmac_sha256_setkey(struct crypto_ahash *tfm,
-               const u8 *key, unsigned int keylen)
+                             const u8 *key, unsigned int keylen)
 {
        return hash_setkey(tfm, key, keylen, HASH_ALGO_SHA256);
 }
@@ -1528,7 +1503,7 @@ static int hash_cra_init(struct crypto_tfm *tfm)
                        hash);
 
        crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
-                       sizeof(struct hash_req_ctx));
+                                sizeof(struct hash_req_ctx));
 
        ctx->config.data_format = HASH_DATA_8_BITS;
        ctx->config.algorithm = hash_alg->conf.algorithm;
@@ -1541,98 +1516,97 @@ static int hash_cra_init(struct crypto_tfm *tfm)
 
 static struct hash_algo_template hash_algs[] = {
        {
-                       .conf.algorithm = HASH_ALGO_SHA1,
-                       .conf.oper_mode = HASH_OPER_MODE_HASH,
-                       .hash = {
-                               .init = hash_init,
-                               .update = ahash_update,
-                               .final = ahash_final,
-                               .digest = ahash_sha1_digest,
-                               .halg.digestsize = SHA1_DIGEST_SIZE,
-                               .halg.statesize = sizeof(struct hash_ctx),
-                               .halg.base = {
-                                       .cra_name = "sha1",
-                                       .cra_driver_name = "sha1-ux500",
-                                       .cra_flags = CRYPTO_ALG_TYPE_AHASH |
-                                                       CRYPTO_ALG_ASYNC,
-                                       .cra_blocksize = SHA1_BLOCK_SIZE,
-                                       .cra_ctxsize = sizeof(struct hash_ctx),
-                                       .cra_init = hash_cra_init,
-                                       .cra_module = THIS_MODULE,
+               .conf.algorithm = HASH_ALGO_SHA1,
+               .conf.oper_mode = HASH_OPER_MODE_HASH,
+               .hash = {
+                       .init = hash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .digest = ahash_sha1_digest,
+                       .halg.digestsize = SHA1_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct hash_ctx),
+                       .halg.base = {
+                               .cra_name = "sha1",
+                               .cra_driver_name = "sha1-ux500",
+                               .cra_flags = (CRYPTO_ALG_TYPE_AHASH |
+                                             CRYPTO_ALG_ASYNC),
+                               .cra_blocksize = SHA1_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct hash_ctx),
+                               .cra_init = hash_cra_init,
+                               .cra_module = THIS_MODULE,
                        }
                }
        },
        {
-                       .conf.algorithm         = HASH_ALGO_SHA256,
-                       .conf.oper_mode         = HASH_OPER_MODE_HASH,
-                       .hash = {
-                               .init = hash_init,
-                               .update = ahash_update,
-                               .final = ahash_final,
-                               .digest = ahash_sha256_digest,
-                               .halg.digestsize = SHA256_DIGEST_SIZE,
-                               .halg.statesize = sizeof(struct hash_ctx),
-                               .halg.base = {
-                                       .cra_name = "sha256",
-                                       .cra_driver_name = "sha256-ux500",
-                                       .cra_flags = CRYPTO_ALG_TYPE_AHASH |
-                                                       CRYPTO_ALG_ASYNC,
-                                       .cra_blocksize = SHA256_BLOCK_SIZE,
-                                       .cra_ctxsize = sizeof(struct hash_ctx),
-                                       .cra_type = &crypto_ahash_type,
-                                       .cra_init = hash_cra_init,
-                                       .cra_module = THIS_MODULE,
-                               }
+               .conf.algorithm = HASH_ALGO_SHA256,
+               .conf.oper_mode = HASH_OPER_MODE_HASH,
+               .hash = {
+                       .init = hash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .digest = ahash_sha256_digest,
+                       .halg.digestsize = SHA256_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct hash_ctx),
+                       .halg.base = {
+                               .cra_name = "sha256",
+                               .cra_driver_name = "sha256-ux500",
+                               .cra_flags = (CRYPTO_ALG_TYPE_AHASH |
+                                             CRYPTO_ALG_ASYNC),
+                               .cra_blocksize = SHA256_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct hash_ctx),
+                               .cra_type = &crypto_ahash_type,
+                               .cra_init = hash_cra_init,
+                               .cra_module = THIS_MODULE,
                        }
-
+               }
        },
        {
-                       .conf.algorithm         = HASH_ALGO_SHA1,
-                       .conf.oper_mode         = HASH_OPER_MODE_HMAC,
+               .conf.algorithm = HASH_ALGO_SHA1,
+               .conf.oper_mode = HASH_OPER_MODE_HMAC,
                        .hash = {
-                               .init = hash_init,
-                               .update = ahash_update,
-                               .final = ahash_final,
-                               .digest = hmac_sha1_digest,
-                               .setkey = hmac_sha1_setkey,
-                               .halg.digestsize = SHA1_DIGEST_SIZE,
-                               .halg.statesize = sizeof(struct hash_ctx),
-                               .halg.base = {
-                                       .cra_name = "hmac(sha1)",
-                                       .cra_driver_name = "hmac-sha1-ux500",
-                                       .cra_flags = CRYPTO_ALG_TYPE_AHASH |
-                                                       CRYPTO_ALG_ASYNC,
-                                       .cra_blocksize = SHA1_BLOCK_SIZE,
-                                       .cra_ctxsize = sizeof(struct hash_ctx),
-                                       .cra_type = &crypto_ahash_type,
-                                       .cra_init = hash_cra_init,
-                                       .cra_module = THIS_MODULE,
-                               }
+                       .init = hash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .digest = hmac_sha1_digest,
+                       .setkey = hmac_sha1_setkey,
+                       .halg.digestsize = SHA1_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct hash_ctx),
+                       .halg.base = {
+                               .cra_name = "hmac(sha1)",
+                               .cra_driver_name = "hmac-sha1-ux500",
+                               .cra_flags = (CRYPTO_ALG_TYPE_AHASH |
+                                             CRYPTO_ALG_ASYNC),
+                               .cra_blocksize = SHA1_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct hash_ctx),
+                               .cra_type = &crypto_ahash_type,
+                               .cra_init = hash_cra_init,
+                               .cra_module = THIS_MODULE,
                        }
+               }
        },
        {
-                       .conf.algorithm         = HASH_ALGO_SHA256,
-                       .conf.oper_mode         = HASH_OPER_MODE_HMAC,
-                       .hash = {
-                               .init = hash_init,
-                               .update = ahash_update,
-                               .final = ahash_final,
-                               .digest = hmac_sha256_digest,
-                               .setkey = hmac_sha256_setkey,
-                               .halg.digestsize = SHA256_DIGEST_SIZE,
-                               .halg.statesize = sizeof(struct hash_ctx),
-                               .halg.base = {
-                                       .cra_name = "hmac(sha256)",
-                                       .cra_driver_name = "hmac-sha256-ux500",
-                                       .cra_flags = CRYPTO_ALG_TYPE_AHASH |
-                                                       CRYPTO_ALG_ASYNC,
-                                       .cra_blocksize = SHA256_BLOCK_SIZE,
-                                       .cra_ctxsize = sizeof(struct hash_ctx),
-                                       .cra_type = &crypto_ahash_type,
-                                       .cra_init = hash_cra_init,
-                                       .cra_module = THIS_MODULE,
-                               }
+               .conf.algorithm = HASH_ALGO_SHA256,
+               .conf.oper_mode = HASH_OPER_MODE_HMAC,
+               .hash = {
+                       .init = hash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .digest = hmac_sha256_digest,
+                       .setkey = hmac_sha256_setkey,
+                       .halg.digestsize = SHA256_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct hash_ctx),
+                       .halg.base = {
+                               .cra_name = "hmac(sha256)",
+                               .cra_driver_name = "hmac-sha256-ux500",
+                               .cra_flags = (CRYPTO_ALG_TYPE_AHASH |
+                                             CRYPTO_ALG_ASYNC),
+                               .cra_blocksize = SHA256_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct hash_ctx),
+                               .cra_type = &crypto_ahash_type,
+                               .cra_init = hash_cra_init,
+                               .cra_module = THIS_MODULE,
                        }
+               }
        }
 };
 
@@ -1649,7 +1623,7 @@ static int ahash_algs_register_all(struct hash_device_data *device_data)
                ret = crypto_register_ahash(&hash_algs[i].hash);
                if (ret) {
                        count = i;
-                       dev_err(device_data->dev, "[%s] alg registration failed",
+                       dev_err(device_data->dev, "%s: alg registration failed\n",
                                hash_algs[i].hash.halg.base.cra_driver_name);
                        goto unreg;
                }
@@ -1683,9 +1657,8 @@ static int ux500_hash_probe(struct platform_device *pdev)
        struct hash_device_data *device_data;
        struct device           *dev = &pdev->dev;
 
-       device_data = kzalloc(sizeof(struct hash_device_data), GFP_ATOMIC);
+       device_data = kzalloc(sizeof(*device_data), GFP_ATOMIC);
        if (!device_data) {
-               dev_dbg(dev, "[%s] kzalloc() failed!", __func__);
                ret = -ENOMEM;
                goto out;
        }
@@ -1695,14 +1668,14 @@ static int ux500_hash_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
-               dev_dbg(dev, "[%s] platform_get_resource() failed!", __func__);
+               dev_dbg(dev, "%s: platform_get_resource() failed!\n", __func__);
                ret = -ENODEV;
                goto out_kfree;
        }
 
        res = request_mem_region(res->start, resource_size(res), pdev->name);
        if (res == NULL) {
-               dev_dbg(dev, "[%s] request_mem_region() failed!", __func__);
+               dev_dbg(dev, "%s: request_mem_region() failed!\n", __func__);
                ret = -EBUSY;
                goto out_kfree;
        }
@@ -1710,8 +1683,7 @@ static int ux500_hash_probe(struct platform_device *pdev)
        device_data->phybase = res->start;
        device_data->base = ioremap(res->start, resource_size(res));
        if (!device_data->base) {
-               dev_err(dev, "[%s] ioremap() failed!",
-                               __func__);
+               dev_err(dev, "%s: ioremap() failed!\n", __func__);
                ret = -ENOMEM;
                goto out_free_mem;
        }
@@ -1721,7 +1693,7 @@ static int ux500_hash_probe(struct platform_device *pdev)
        /* Enable power for HASH1 hardware block */
        device_data->regulator = regulator_get(dev, "v-ape");
        if (IS_ERR(device_data->regulator)) {
-               dev_err(dev, "[%s] regulator_get() failed!", __func__);
+               dev_err(dev, "%s: regulator_get() failed!\n", __func__);
                ret = PTR_ERR(device_data->regulator);
                device_data->regulator = NULL;
                goto out_unmap;
@@ -1730,27 +1702,27 @@ static int ux500_hash_probe(struct platform_device *pdev)
        /* Enable the clock for HASH1 hardware block */
        device_data->clk = clk_get(dev, NULL);
        if (IS_ERR(device_data->clk)) {
-               dev_err(dev, "[%s] clk_get() failed!", __func__);
+               dev_err(dev, "%s: clk_get() failed!\n", __func__);
                ret = PTR_ERR(device_data->clk);
                goto out_regulator;
        }
 
        ret = clk_prepare(device_data->clk);
        if (ret) {
-               dev_err(dev, "[%s] clk_prepare() failed!", __func__);
+               dev_err(dev, "%s: clk_prepare() failed!\n", __func__);
                goto out_clk;
        }
 
        /* Enable device power (and clock) */
        ret = hash_enable_power(device_data, false);
        if (ret) {
-               dev_err(dev, "[%s]: hash_enable_power() failed!", __func__);
+               dev_err(dev, "%s: hash_enable_power() failed!\n", __func__);
                goto out_clk_unprepare;
        }
 
        ret = hash_check_hw(device_data);
        if (ret) {
-               dev_err(dev, "[%s] hash_check_hw() failed!", __func__);
+               dev_err(dev, "%s: hash_check_hw() failed!\n", __func__);
                goto out_power;
        }
 
@@ -1766,8 +1738,8 @@ static int ux500_hash_probe(struct platform_device *pdev)
 
        ret = ahash_algs_register_all(device_data);
        if (ret) {
-               dev_err(dev, "[%s] ahash_algs_register_all() "
-                               "failed!", __func__);
+               dev_err(dev, "%s: ahash_algs_register_all() failed!\n",
+                       __func__);
                goto out_power;
        }
 
@@ -1810,8 +1782,7 @@ static int ux500_hash_remove(struct platform_device *pdev)
 
        device_data = platform_get_drvdata(pdev);
        if (!device_data) {
-               dev_err(dev, "[%s]: platform_get_drvdata() failed!",
-                       __func__);
+               dev_err(dev, "%s: platform_get_drvdata() failed!\n", __func__);
                return -ENOMEM;
        }
 
@@ -1841,7 +1812,7 @@ static int ux500_hash_remove(struct platform_device *pdev)
                ahash_algs_unregister_all(device_data);
 
        if (hash_disable_power(device_data, false))
-               dev_err(dev, "[%s]: hash_disable_power() failed",
+               dev_err(dev, "%s: hash_disable_power() failed\n",
                        __func__);
 
        clk_unprepare(device_data->clk);
@@ -1870,8 +1841,8 @@ static void ux500_hash_shutdown(struct platform_device *pdev)
 
        device_data = platform_get_drvdata(pdev);
        if (!device_data) {
-               dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
-                               __func__);
+               dev_err(&pdev->dev, "%s: platform_get_drvdata() failed!\n",
+                       __func__);
                return;
        }
 
@@ -1880,8 +1851,8 @@ static void ux500_hash_shutdown(struct platform_device *pdev)
        /* current_ctx allocates a device, NULL = unallocated */
        if (!device_data->current_ctx) {
                if (down_trylock(&driver_data.device_allocation))
-                       dev_dbg(&pdev->dev, "[%s]: Cryp still in use!"
-                               "Shutting down anyway...", __func__);
+                       dev_dbg(&pdev->dev, "%s: Cryp still in use! Shutting down anyway...\n",
+                               __func__);
                /**
                 * (Allocate the device)
                 * Need to set this to non-null (dummy) value,
@@ -1906,8 +1877,8 @@ static void ux500_hash_shutdown(struct platform_device *pdev)
                release_mem_region(res->start, resource_size(res));
 
        if (hash_disable_power(device_data, false))
-               dev_err(&pdev->dev, "[%s] hash_disable_power() failed",
-                               __func__);
+               dev_err(&pdev->dev, "%s: hash_disable_power() failed\n",
+                       __func__);
 }
 
 /**
@@ -1922,7 +1893,7 @@ static int ux500_hash_suspend(struct device *dev)
 
        device_data = dev_get_drvdata(dev);
        if (!device_data) {
-               dev_err(dev, "[%s] platform_get_drvdata() failed!", __func__);
+               dev_err(dev, "%s: platform_get_drvdata() failed!\n", __func__);
                return -ENOMEM;
        }
 
@@ -1933,15 +1904,16 @@ static int ux500_hash_suspend(struct device *dev)
 
        if (device_data->current_ctx == ++temp_ctx) {
                if (down_interruptible(&driver_data.device_allocation))
-                       dev_dbg(dev, "[%s]: down_interruptible() failed",
+                       dev_dbg(dev, "%s: down_interruptible() failed\n",
                                __func__);
                ret = hash_disable_power(device_data, false);
 
-       } else
+       } else {
                ret = hash_disable_power(device_data, true);
+       }
 
        if (ret)
-               dev_err(dev, "[%s]: hash_disable_power()", __func__);
+               dev_err(dev, "%s: hash_disable_power()\n", __func__);
 
        return ret;
 }
@@ -1958,7 +1930,7 @@ static int ux500_hash_resume(struct device *dev)
 
        device_data = dev_get_drvdata(dev);
        if (!device_data) {
-               dev_err(dev, "[%s] platform_get_drvdata() failed!", __func__);
+               dev_err(dev, "%s: platform_get_drvdata() failed!\n", __func__);
                return -ENOMEM;
        }
 
@@ -1973,7 +1945,7 @@ static int ux500_hash_resume(struct device *dev)
                ret = hash_enable_power(device_data, true);
 
        if (ret)
-               dev_err(dev, "[%s]: hash_enable_power() failed!", __func__);
+               dev_err(dev, "%s: hash_enable_power() failed!\n", __func__);
 
        return ret;
 }
@@ -1981,8 +1953,8 @@ static int ux500_hash_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(ux500_hash_pm, ux500_hash_suspend, ux500_hash_resume);
 
 static const struct of_device_id ux500_hash_match[] = {
-        { .compatible = "stericsson,ux500-hash" },
-        { },
+       { .compatible = "stericsson,ux500-hash" },
+       { },
 };
 
 static struct platform_driver hash_driver = {
index daa4da281e5ebedf83e791b2e94af1ed6f45d990..f238cfd33847ec3c5333158ea39dac72245c8eee 100644 (file)
@@ -198,6 +198,7 @@ config TI_EDMA
        depends on ARCH_DAVINCI || ARCH_OMAP
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
+       select TI_PRIV_EDMA
        default n
        help
          Enable support for the TI EDMA controller. This DMA
@@ -308,6 +309,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..3519111c566b8a3bc9a43b8b89bc2b866c3d833e 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,17 +296,24 @@ 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),
                                                EDMA_SLOT_ANY);
                        if (echan->slot[i] < 0) {
                                dev_err(dev, "Failed to allocate slot\n");
+                               kfree(edesc);
                                return NULL;
                        }
                }
+       }
+
+       /* Configure PaRAM sets for each SG */
+       for_each_sg(sgl, sg, sg_len, i) {
 
                acnt = dev_width;
 
@@ -330,6 +371,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 +402,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 +587,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);
 
@@ -667,6 +750,6 @@ static void __exit edma_exit(void)
 }
 module_exit(edma_exit);
 
-MODULE_AUTHOR("Matt Porter <mporter@ti.com>");
+MODULE_AUTHOR("Matt Porter <matt.porter@linaro.org>");
 MODULE_DESCRIPTION("TI EDMA DMA engine driver");
 MODULE_LICENSE("GPL v2");
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..55852c02679143f453286f189e68fd777ea1afaa 100644 (file)
@@ -437,17 +437,18 @@ static void dma_irq_handle_channel(struct imxdma_channel *imxdmac)
        struct imxdma_engine *imxdma = imxdmac->imxdma;
        int chno = imxdmac->channel;
        struct imxdma_desc *desc;
+       unsigned long flags;
 
-       spin_lock(&imxdma->lock);
+       spin_lock_irqsave(&imxdma->lock, flags);
        if (list_empty(&imxdmac->ld_active)) {
-               spin_unlock(&imxdma->lock);
+               spin_unlock_irqrestore(&imxdma->lock, flags);
                goto out;
        }
 
        desc = list_first_entry(&imxdmac->ld_active,
                                struct imxdma_desc,
                                node);
-       spin_unlock(&imxdma->lock);
+       spin_unlock_irqrestore(&imxdma->lock, flags);
 
        if (desc->sg) {
                u32 tmp;
@@ -519,7 +520,6 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
 {
        struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
        struct imxdma_engine *imxdma = imxdmac->imxdma;
-       unsigned long flags;
        int slot = -1;
        int i;
 
@@ -527,7 +527,6 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
        switch (d->type) {
        case IMXDMA_DESC_INTERLEAVED:
                /* Try to get a free 2D slot */
-               spin_lock_irqsave(&imxdma->lock, flags);
                for (i = 0; i < IMX_DMA_2D_SLOTS; i++) {
                        if ((imxdma->slots_2d[i].count > 0) &&
                        ((imxdma->slots_2d[i].xsr != d->x) ||
@@ -537,10 +536,8 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
                        slot = i;
                        break;
                }
-               if (slot < 0) {
-                       spin_unlock_irqrestore(&imxdma->lock, flags);
+               if (slot < 0)
                        return -EBUSY;
-               }
 
                imxdma->slots_2d[slot].xsr = d->x;
                imxdma->slots_2d[slot].ysr = d->y;
@@ -549,7 +546,6 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
 
                imxdmac->slot_2d = slot;
                imxdmac->enabled_2d = true;
-               spin_unlock_irqrestore(&imxdma->lock, flags);
 
                if (slot == IMX_DMA_2D_SLOT_A) {
                        d->config_mem &= ~CCR_MSEL_B;
@@ -625,18 +621,17 @@ static void imxdma_tasklet(unsigned long data)
        struct imxdma_channel *imxdmac = (void *)data;
        struct imxdma_engine *imxdma = imxdmac->imxdma;
        struct imxdma_desc *desc;
+       unsigned long flags;
 
-       spin_lock(&imxdma->lock);
+       spin_lock_irqsave(&imxdma->lock, flags);
 
        if (list_empty(&imxdmac->ld_active)) {
                /* Someone might have called terminate all */
-               goto out;
+               spin_unlock_irqrestore(&imxdma->lock, flags);
+               return;
        }
        desc = list_first_entry(&imxdmac->ld_active, struct imxdma_desc, node);
 
-       if (desc->desc.callback)
-               desc->desc.callback(desc->desc.callback_param);
-
        /* If we are dealing with a cyclic descriptor, keep it on ld_active
         * and dont mark the descriptor as complete.
         * Only in non-cyclic cases it would be marked as complete
@@ -663,7 +658,11 @@ static void imxdma_tasklet(unsigned long data)
                                 __func__, imxdmac->channel);
        }
 out:
-       spin_unlock(&imxdma->lock);
+       spin_unlock_irqrestore(&imxdma->lock, flags);
+
+       if (desc->desc.callback)
+               desc->desc.callback(desc->desc.callback_param);
+
 }
 
 static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
@@ -805,10 +804,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(
@@ -885,7 +882,7 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
        kfree(imxdmac->sg_list);
 
        imxdmac->sg_list = kcalloc(periods + 1,
-                       sizeof(struct scatterlist), GFP_KERNEL);
+                       sizeof(struct scatterlist), GFP_ATOMIC);
        if (!imxdmac->sg_list)
                return NULL;
 
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..ebad845
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * 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 */
+       dma_addr_t slave_addr;
+};
+
+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");
+               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,
+                             dma_addr_t slave_addr, 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;
+       chan->slave_addr = slave_addr ? : sc->addr;
+       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->slave_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_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,
+};
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 */
similarity index 88%
rename from drivers/dma/sh/shdma.c
rename to drivers/dma/sh/shdmac.c
index 5039fbc88254eabd570e9da6d50d51ed0cff8240..1069e8869f20762928ecbbe509b2ed294f82ae35 100644 (file)
@@ -20,6 +20,8 @@
 
 #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 "../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 */
 static DEFINE_SPINLOCK(sh_dmae_lock);
 static LIST_HEAD(sh_dmae_devices);
 
-static void chclr_write(struct sh_dmae_chan *sh_dc, u32 data)
+/*
+ * 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(data, shdev->chan_reg +
-                    shdev->pdata->channel[sh_dc->shdma_chan.id].chclr_offset);
+       __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 / sizeof(u32));
+       __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 / sizeof(u32));
+       return __raw_readl(sh_dc->base + reg);
 }
 
 static u16 dmaor_read(struct sh_dmae_device *shdev)
 {
-       u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
+       void __iomem *addr = shdev->chan_reg + DMAOR;
 
        if (shdev->pdata->dmaor_is_32bit)
                return __raw_readl(addr);
@@ -79,7 +100,7 @@ static u16 dmaor_read(struct sh_dmae_device *shdev)
 
 static void dmaor_write(struct sh_dmae_device *shdev, u16 data)
 {
-       u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
+       void __iomem *addr = shdev->chan_reg + DMAOR;
 
        if (shdev->pdata->dmaor_is_32bit)
                __raw_writel(data, addr);
@@ -91,14 +112,14 @@ 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));
+       __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 / sizeof(u32));
+       return __raw_readl(sh_dc->base + shdev->chcr_offset);
 }
 
 /*
@@ -133,7 +154,7 @@ static int sh_dmae_rst(struct sh_dmae_device *shdev)
                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);
+                               channel_clear(sh_chan);
                }
        }
 
@@ -167,7 +188,7 @@ static bool dmae_is_busy(struct sh_dmae_chan *sh_chan)
 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;
+       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);
 
@@ -180,7 +201,7 @@ static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
 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;
+       const struct sh_dmae_pdata *pdata = shdev->pdata;
        int i;
 
        for (i = 0; i < pdata->ts_shift_num; i++)
@@ -240,9 +261,9 @@ static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
 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_pdata *pdata = shdev->pdata;
        const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->shdma_chan.id];
-       u16 __iomem *addr = shdev->dmars;
+       void __iomem *addr = shdev->dmars;
        unsigned int shift = chan_pdata->dmars_bit;
 
        if (dmae_is_busy(sh_chan))
@@ -253,8 +274,8 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
 
        /* 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);
+               addr = shdev->chan_reg;
+       addr += chan_pdata->dmars;
 
        __raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift),
                     addr);
@@ -309,7 +330,7 @@ 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_pdata *pdata = shdev->pdata;
        const struct sh_dmae_slave_config *cfg;
        int i;
 
@@ -323,7 +344,7 @@ static const struct sh_dmae_slave_config *dmae_find_slave(
        } 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;
+                               sh_chan->shdma_chan.slave_id = i;
                                return cfg;
                        }
        }
@@ -332,7 +353,7 @@ static const struct sh_dmae_slave_config *dmae_find_slave(
 }
 
 static int sh_dmae_set_slave(struct shdma_chan *schan,
-                            int slave_id, bool try)
+                            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);
@@ -340,8 +361,10 @@ static int sh_dmae_set_slave(struct shdma_chan *schan,
        if (!cfg)
                return -ENXIO;
 
-       if (!try)
+       if (!try) {
                sh_chan->config = cfg;
+               sh_chan->slave_addr = slave_addr ? : cfg->addr;
+       }
 
        return 0;
 }
@@ -505,7 +528,8 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
        struct shdma_chan *schan;
        int err;
 
-       sh_chan = kzalloc(sizeof(struct sh_dmae_chan), GFP_KERNEL);
+       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");
@@ -517,7 +541,7 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
 
        shdma_chan_probe(sdev, schan, id);
 
-       sh_chan->base = shdev->chan_reg + chan_pdata->offset / sizeof(u32);
+       sh_chan->base = shdev->chan_reg + chan_pdata->offset;
 
        /* set up channel irq */
        if (pdev->id >= 0)
@@ -541,7 +565,6 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
 err_no_irq:
        /* remove from dmaengine device node */
        shdma_chan_remove(schan);
-       kfree(sh_chan);
        return err;
 }
 
@@ -552,14 +575,9 @@ static void sh_dmae_chan_remove(struct sh_dmae_device *shdev)
        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;
 }
@@ -636,7 +654,7 @@ static dma_addr_t sh_dmae_slave_addr(struct shdma_chan *schan)
         * This is an exclusive slave DMA operation, may only be called after a
         * successful slave configuration.
         */
-       return sh_chan->config->addr;
+       return sh_chan->slave_addr;
 }
 
 static struct shdma_desc *sh_dmae_embedded_desc(void *buf, int i)
@@ -658,9 +676,15 @@ static const struct shdma_ops sh_dmae_shdma_ops = {
        .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)
 {
-       struct sh_dmae_pdata *pdata = pdev->dev.platform_data;
+       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];
@@ -669,6 +693,11 @@ static int sh_dmae_probe(struct platform_device *pdev)
        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;
@@ -696,33 +725,22 @@ static int sh_dmae_probe(struct platform_device *pdev)
        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);
+       shdev = devm_kzalloc(&pdev->dev, sizeof(struct sh_dmae_device),
+                            GFP_KERNEL);
        if (!shdev) {
                dev_err(&pdev->dev, "Not enough memory\n");
-               goto ealloc;
+               return -ENOMEM;
        }
 
        dma_dev = &shdev->shdma_dev.dma_dev;
 
-       shdev->chan_reg = ioremap(chan->start, resource_size(chan));
-       if (!shdev->chan_reg)
-               goto emapchan;
+       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 = ioremap(dmars->start, resource_size(dmars));
-               if (!shdev->dmars)
-                       goto emapdmars;
+               shdev->dmars = devm_ioremap_resource(&pdev->dev, dmars);
+               if (IS_ERR(shdev->dmars))
+                       return PTR_ERR(shdev->dmars);
        }
 
        if (!pdata->slave_only)
@@ -783,8 +801,8 @@ static int sh_dmae_probe(struct platform_device *pdev)
 
        errirq = errirq_res->start;
 
-       err = request_irq(errirq, sh_dmae_err, irqflags,
-                         "DMAC Address Error", shdev);
+       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",
@@ -862,7 +880,6 @@ 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:
@@ -873,21 +890,9 @@ rst_err:
        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;
 }
@@ -896,14 +901,9 @@ 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);
@@ -913,31 +913,11 @@ static int sh_dmae_remove(struct platform_device *pdev)
        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,
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 b2450ba14138ba241b691c462865a8dbed157cf0..b6ed304863eb97dc68e4afd0f35e359ca53903fd 100644 (file)
@@ -146,6 +146,16 @@ config GPIO_MM_LANTIQ
          (EBU) found on Lantiq SoCs. The gpios are output only as they are
          created by attaching a 16bit latch to the bus.
 
+config GPIO_F7188X
+       tristate "F71882FG and F71889F GPIO support"
+       depends on X86
+       help
+         This option enables support for GPIOs found on Fintek Super-I/O
+         chips F71882FG and F71889F.
+
+         To compile this driver as a module, choose M here: the module will
+         be called f7188x-gpio.
+
 config GPIO_MPC5200
        def_bool y
        depends on PPC_MPC52xx
@@ -193,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
@@ -242,6 +260,21 @@ config GPIO_TS5500
          blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600
          LCD port.
 
+config GPIO_TZ1090
+       bool "Toumaz Xenif TZ1090 GPIO support"
+       depends on SOC_TZ1090
+       select GENERIC_IRQ_CHIP
+       default y
+       help
+         Say yes here to support Toumaz Xenif TZ1090 GPIOs.
+
+config GPIO_TZ1090_PDC
+       bool "Toumaz Xenif TZ1090 PDC GPIO support"
+       depends on SOC_TZ1090
+       default y
+       help
+         Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs.
+
 config GPIO_XILINX
        bool "Xilinx GPIO support"
        depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ
@@ -289,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
@@ -363,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.
@@ -628,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
@@ -676,6 +709,18 @@ config GPIO_UCB1400
          This enables support for the Philips UCB1400 GPIO pins.
          The UCB1400 is an AC97 audio codec.
 
+comment "LPC GPIO expanders:"
+
+config GPIO_KEMPLD
+       tristate "Kontron ETX / COMexpress GPIO"
+       depends on MFD_KEMPLD
+       help
+         This enables support for the PLD GPIO interface on some Kontron ETX
+         and COMexpress (ETXexpress) modules.
+
+         This driver can also be built as a module. If so, the module will be
+         called gpio-kempld.
+
 comment "MODULbus GPIO expanders:"
 
 config GPIO_JANZ_TTL
index ef3e983a2f1ead46b6e39d650de2c67b757883b7..98e23ebba2cffa73eec7f0a9a113f820f9a14404 100644 (file)
@@ -24,11 +24,13 @@ obj-$(CONFIG_GPIO_DA9055)   += gpio-da9055.o
 obj-$(CONFIG_ARCH_DAVINCI)     += gpio-davinci.o
 obj-$(CONFIG_GPIO_EM)          += gpio-em.o
 obj-$(CONFIG_GPIO_EP93XX)      += gpio-ep93xx.o
+obj-$(CONFIG_GPIO_F7188X)      += gpio-f7188x.o
 obj-$(CONFIG_GPIO_GE_FPGA)     += gpio-ge.o
 obj-$(CONFIG_GPIO_GRGPIO)      += gpio-grgpio.o
 obj-$(CONFIG_GPIO_ICH)         += gpio-ich.o
 obj-$(CONFIG_GPIO_IT8761E)     += gpio-it8761e.o
 obj-$(CONFIG_GPIO_JANZ_TTL)    += gpio-janz-ttl.o
+obj-$(CONFIG_GPIO_KEMPLD)      += gpio-kempld.o
 obj-$(CONFIG_ARCH_KS8695)      += gpio-ks8695.o
 obj-$(CONFIG_GPIO_LANGWELL)    += gpio-langwell.o
 obj-$(CONFIG_ARCH_LPC32XX)     += gpio-lpc32xx.o
@@ -50,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
@@ -79,6 +82,8 @@ obj-$(CONFIG_GPIO_TPS65912)   += gpio-tps65912.o
 obj-$(CONFIG_GPIO_TS5500)      += gpio-ts5500.o
 obj-$(CONFIG_GPIO_TWL4030)     += gpio-twl4030.o
 obj-$(CONFIG_GPIO_TWL6040)     += gpio-twl6040.o
+obj-$(CONFIG_GPIO_TZ1090)      += gpio-tz1090.o
+obj-$(CONFIG_GPIO_TZ1090_PDC)  += gpio-tz1090-pdc.o
 obj-$(CONFIG_GPIO_UCB1400)     += gpio-ucb1400.o
 obj-$(CONFIG_GPIO_VIPERBOARD)  += gpio-viperboard.o
 obj-$(CONFIG_GPIO_VR41XX)      += gpio-vr41xx.o
index 721607904d0a4837590f0a295e394c727a537f38..5d518d5db7a0ae4a084f3652cb2ac61067a3dbc6 100644 (file)
@@ -129,7 +129,7 @@ static int gen_74x164_probe(struct spi_device *spi)
        if (!chip)
                return -ENOMEM;
 
-       pdata = spi->dev.platform_data;
+       pdata = dev_get_platdata(&spi->dev);
        if (pdata && pdata->base)
                chip->gpio_chip.base = pdata->base;
        else
index e60567fc50736904741d0e1a8e70bb19ddf3c743..c0f3fc44ab0eca1957a1bbf192dca1bc6be04291 100644 (file)
@@ -490,15 +490,11 @@ static int adnp_irq_setup(struct adnp *adnp)
        if (err != 0) {
                dev_err(chip->dev, "can't request IRQ#%d: %d\n",
                        adnp->client->irq, err);
-               goto error;
+               return err;
        }
 
        chip->to_irq = adnp_gpio_to_irq;
        return 0;
-
-error:
-       irq_domain_remove(adnp->domain);
-       return err;
 }
 
 static void adnp_irq_teardown(struct adnp *adnp)
index f33f78dcadaad817ed331c40daa0447d126282a6..084337d5514d8d1c373413d4c66d1ec1aa317163 100644 (file)
@@ -89,7 +89,7 @@ static int adp5520_gpio_direction_output(struct gpio_chip *chip,
 
 static int adp5520_gpio_probe(struct platform_device *pdev)
 {
-       struct adp5520_gpio_platform_data *pdata = pdev->dev.platform_data;
+       struct adp5520_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct adp5520_gpio *dev;
        struct gpio_chip *gc;
        int ret, i, gpios;
index 2ba56987db04dded1c231d38315f124260e0e432..90fc4c99c024ee39605381c247236644e4c927b4 100644 (file)
@@ -276,7 +276,8 @@ static irqreturn_t adp5588_irq_handler(int irq, void *devid)
 static int adp5588_irq_setup(struct adp5588_gpio *dev)
 {
        struct i2c_client *client = dev->client;
-       struct adp5588_gpio_platform_data *pdata = client->dev.platform_data;
+       struct adp5588_gpio_platform_data *pdata =
+                       dev_get_platdata(&client->dev);
        unsigned gpio;
        int ret;
 
@@ -349,7 +350,8 @@ static void adp5588_irq_teardown(struct adp5588_gpio *dev)
 static int adp5588_gpio_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
-       struct adp5588_gpio_platform_data *pdata = client->dev.platform_data;
+       struct adp5588_gpio_platform_data *pdata =
+                       dev_get_platdata(&client->dev);
        struct adp5588_gpio *dev;
        struct gpio_chip *gc;
        int ret, i, revid;
@@ -440,7 +442,8 @@ err:
 
 static int adp5588_gpio_remove(struct i2c_client *client)
 {
-       struct adp5588_gpio_platform_data *pdata = client->dev.platform_data;
+       struct adp5588_gpio_platform_data *pdata =
+                       dev_get_platdata(&client->dev);
        struct adp5588_gpio *dev = i2c_get_clientdata(client);
        int ret;
 
index 0ea853f68db2cf63993f29ca8cfcadce1e8e0f2f..fa8b6a762761412a84901e7629b23270b66ac2ec 100644 (file)
@@ -97,7 +97,7 @@ static struct gpio_chip template_chip = {
 static int arizona_gpio_probe(struct platform_device *pdev)
 {
        struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
-       struct arizona_pdata *pdata = arizona->dev->platform_data;
+       struct arizona_pdata *pdata = dev_get_platdata(arizona->dev);
        struct arizona_gpio *arizona_gpio;
        int ret;
 
index 29b11e9b6a78600b2d14d61a178d5e1de3fdc2bc..9b77dc05d4ada6c6744040cf2cdfb5d76c3188a4 100644 (file)
@@ -216,7 +216,7 @@ static int da9052_gpio_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        gpio->da9052 = dev_get_drvdata(pdev->dev.parent);
-       pdata = gpio->da9052->dev->platform_data;
+       pdata = dev_get_platdata(gpio->da9052->dev);
 
        gpio->gp = reference_gp;
        if (pdata && pdata->gpio_base)
index fd6dfe382f13c650170a4f0f20cf3ed6a612dba5..7ef0820032bd157a7adadc368cc521d0a7ff57aa 100644 (file)
@@ -150,7 +150,7 @@ static int da9055_gpio_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        gpio->da9055 = dev_get_drvdata(pdev->dev.parent);
-       pdata = gpio->da9055->dev->platform_data;
+       pdata = dev_get_platdata(gpio->da9055->dev);
 
        gpio->gp = reference_gp;
        if (pdata && pdata->gpio_base)
index 5cba855638bf93b47e72c64ccd508f11db42f771..c6e1f086efe8455733c3f27080f301a1922ea6db 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_data/gpio-em.h>
 
 struct em_gio_priv {
@@ -216,6 +217,21 @@ static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset)
        return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset);
 }
 
+static int em_gio_request(struct gpio_chip *chip, unsigned offset)
+{
+       return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void em_gio_free(struct gpio_chip *chip, unsigned offset)
+{
+       pinctrl_free_gpio(chip->base + offset);
+
+       /* Set the GPIO as an input to ensure that the next GPIO request won't
+       * drive the GPIO pin as an output.
+       */
+       em_gio_direction_input(chip, offset);
+}
+
 static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq,
                                 irq_hw_number_t hw)
 {
@@ -237,7 +253,7 @@ static struct irq_domain_ops em_gio_irq_domain_ops = {
 static int em_gio_probe(struct platform_device *pdev)
 {
        struct gpio_em_config pdata_dt;
-       struct gpio_em_config *pdata = pdev->dev.platform_data;
+       struct gpio_em_config *pdata = dev_get_platdata(&pdev->dev);
        struct em_gio_priv *p;
        struct resource *io[2], *irq[2];
        struct gpio_chip *gpio_chip;
@@ -308,6 +324,8 @@ static int em_gio_probe(struct platform_device *pdev)
        gpio_chip->direction_output = em_gio_direction_output;
        gpio_chip->set = em_gio_set;
        gpio_chip->to_irq = em_gio_to_irq;
+       gpio_chip->request = em_gio_request;
+       gpio_chip->free = em_gio_free;
        gpio_chip->label = name;
        gpio_chip->owner = THIS_MODULE;
        gpio_chip->base = pdata->gpio_base;
@@ -351,6 +369,13 @@ static int em_gio_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "failed to add GPIO controller\n");
                goto err1;
        }
+
+       if (pdata->pctl_name) {
+               ret = gpiochip_add_pin_range(gpio_chip, pdata->pctl_name, 0,
+                                            gpio_chip->base, gpio_chip->ngpio);
+               if (ret < 0)
+                       dev_warn(&pdev->dev, "failed to add pin range\n");
+       }
        return 0;
 
 err1:
diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
new file mode 100644 (file)
index 0000000..9cb8320
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * GPIO driver for Fintek Super-I/O F71882 and F71889
+ *
+ * Copyright (C) 2010-2013 LaCie
+ *
+ * Author: Simon Guinot <simon.guinot@sequanux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#define DRVNAME "gpio-f7188x"
+
+/*
+ * Super-I/O registers
+ */
+#define SIO_LDSEL              0x07    /* Logical device select */
+#define SIO_DEVID              0x20    /* Device ID (2 bytes) */
+#define SIO_DEVREV             0x22    /* Device revision */
+#define SIO_MANID              0x23    /* Fintek ID (2 bytes) */
+
+#define SIO_LD_GPIO            0x06    /* GPIO logical device */
+#define SIO_UNLOCK_KEY         0x87    /* Key to enable Super-I/O */
+#define SIO_LOCK_KEY           0xAA    /* Key to disable Super-I/O */
+
+#define SIO_FINTEK_ID          0x1934  /* Manufacturer ID */
+#define SIO_F71882_ID          0x0541  /* F71882 chipset ID */
+#define SIO_F71889_ID          0x0909  /* F71889 chipset ID */
+
+enum chips { f71882fg, f71889f };
+
+static const char * const f7188x_names[] = {
+       "f71882fg",
+       "f71889f",
+};
+
+struct f7188x_sio {
+       int addr;
+       enum chips type;
+};
+
+struct f7188x_gpio_bank {
+       struct gpio_chip chip;
+       unsigned int regbase;
+       struct f7188x_gpio_data *data;
+};
+
+struct f7188x_gpio_data {
+       struct f7188x_sio *sio;
+       int nr_bank;
+       struct f7188x_gpio_bank *bank;
+};
+
+/*
+ * Super-I/O functions.
+ */
+
+static inline int superio_inb(int base, int reg)
+{
+       outb(reg, base);
+       return inb(base + 1);
+}
+
+static int superio_inw(int base, int reg)
+{
+       int val;
+
+       outb(reg++, base);
+       val = inb(base + 1) << 8;
+       outb(reg, base);
+       val |= inb(base + 1);
+
+       return val;
+}
+
+static inline void superio_outb(int base, int reg, int val)
+{
+       outb(reg, base);
+       outb(val, base + 1);
+}
+
+static inline int superio_enter(int base)
+{
+       /* Don't step on other drivers' I/O space by accident. */
+       if (!request_muxed_region(base, 2, DRVNAME)) {
+               pr_err(DRVNAME "I/O address 0x%04x already in use\n", base);
+               return -EBUSY;
+       }
+
+       /* According to the datasheet the key must be send twice. */
+       outb(SIO_UNLOCK_KEY, base);
+       outb(SIO_UNLOCK_KEY, base);
+
+       return 0;
+}
+
+static inline void superio_select(int base, int ld)
+{
+       outb(SIO_LDSEL, base);
+       outb(ld, base + 1);
+}
+
+static inline void superio_exit(int base)
+{
+       outb(SIO_LOCK_KEY, base);
+       release_region(base, 2);
+}
+
+/*
+ * GPIO chip.
+ */
+
+static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset);
+static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset);
+static int f7188x_gpio_direction_out(struct gpio_chip *chip,
+                                    unsigned offset, int value);
+static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value);
+
+#define F7188X_GPIO_BANK(_base, _ngpio, _regbase)                      \
+       {                                                               \
+               .chip = {                                               \
+                       .label            = DRVNAME,                    \
+                       .owner            = THIS_MODULE,                \
+                       .direction_input  = f7188x_gpio_direction_in,   \
+                       .get              = f7188x_gpio_get,            \
+                       .direction_output = f7188x_gpio_direction_out,  \
+                       .set              = f7188x_gpio_set,            \
+                       .base             = _base,                      \
+                       .ngpio            = _ngpio,                     \
+               },                                                      \
+               .regbase = _regbase,                                    \
+       }
+
+#define gpio_dir(base) (base + 0)
+#define gpio_data_out(base) (base + 1)
+#define gpio_data_in(base) (base + 2)
+/* Output mode register (0:open drain 1:push-pull). */
+#define gpio_out_mode(base) (base + 3)
+
+static struct f7188x_gpio_bank f71882_gpio_bank[] = {
+       F7188X_GPIO_BANK(0 , 8, 0xF0),
+       F7188X_GPIO_BANK(10, 8, 0xE0),
+       F7188X_GPIO_BANK(20, 8, 0xD0),
+       F7188X_GPIO_BANK(30, 4, 0xC0),
+       F7188X_GPIO_BANK(40, 4, 0xB0),
+};
+
+static struct f7188x_gpio_bank f71889_gpio_bank[] = {
+       F7188X_GPIO_BANK(0 , 7, 0xF0),
+       F7188X_GPIO_BANK(10, 7, 0xE0),
+       F7188X_GPIO_BANK(20, 8, 0xD0),
+       F7188X_GPIO_BANK(30, 8, 0xC0),
+       F7188X_GPIO_BANK(40, 8, 0xB0),
+       F7188X_GPIO_BANK(50, 5, 0xA0),
+       F7188X_GPIO_BANK(60, 8, 0x90),
+       F7188X_GPIO_BANK(70, 8, 0x80),
+};
+
+static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+       int err;
+       struct f7188x_gpio_bank *bank =
+               container_of(chip, struct f7188x_gpio_bank, chip);
+       struct f7188x_sio *sio = bank->data->sio;
+       u8 dir;
+
+       err = superio_enter(sio->addr);
+       if (err)
+               return err;
+       superio_select(sio->addr, SIO_LD_GPIO);
+
+       dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
+       dir &= ~(1 << offset);
+       superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
+
+       superio_exit(sio->addr);
+
+       return 0;
+}
+
+static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       int err;
+       struct f7188x_gpio_bank *bank =
+               container_of(chip, struct f7188x_gpio_bank, chip);
+       struct f7188x_sio *sio = bank->data->sio;
+       u8 dir, data;
+
+       err = superio_enter(sio->addr);
+       if (err)
+               return err;
+       superio_select(sio->addr, SIO_LD_GPIO);
+
+       dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
+       dir = !!(dir & (1 << offset));
+       if (dir)
+               data = superio_inb(sio->addr, gpio_data_out(bank->regbase));
+       else
+               data = superio_inb(sio->addr, gpio_data_in(bank->regbase));
+
+       superio_exit(sio->addr);
+
+       return !!(data & 1 << offset);
+}
+
+static int f7188x_gpio_direction_out(struct gpio_chip *chip,
+                                    unsigned offset, int value)
+{
+       int err;
+       struct f7188x_gpio_bank *bank =
+               container_of(chip, struct f7188x_gpio_bank, chip);
+       struct f7188x_sio *sio = bank->data->sio;
+       u8 dir, data_out;
+
+       err = superio_enter(sio->addr);
+       if (err)
+               return err;
+       superio_select(sio->addr, SIO_LD_GPIO);
+
+       data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
+       if (value)
+               data_out |= (1 << offset);
+       else
+               data_out &= ~(1 << offset);
+       superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
+
+       dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
+       dir |= (1 << offset);
+       superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
+
+       superio_exit(sio->addr);
+
+       return 0;
+}
+
+static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       int err;
+       struct f7188x_gpio_bank *bank =
+               container_of(chip, struct f7188x_gpio_bank, chip);
+       struct f7188x_sio *sio = bank->data->sio;
+       u8 data_out;
+
+       err = superio_enter(sio->addr);
+       if (err)
+               return;
+       superio_select(sio->addr, SIO_LD_GPIO);
+
+       data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
+       if (value)
+               data_out |= (1 << offset);
+       else
+               data_out &= ~(1 << offset);
+       superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
+
+       superio_exit(sio->addr);
+}
+
+/*
+ * Platform device and driver.
+ */
+
+static int f7188x_gpio_probe(struct platform_device *pdev)
+{
+       int err;
+       int i;
+       struct f7188x_sio *sio = pdev->dev.platform_data;
+       struct f7188x_gpio_data *data;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       switch (sio->type) {
+       case f71882fg:
+               data->nr_bank = ARRAY_SIZE(f71882_gpio_bank);
+               data->bank = f71882_gpio_bank;
+               break;
+       case f71889f:
+               data->nr_bank = ARRAY_SIZE(f71889_gpio_bank);
+               data->bank = f71889_gpio_bank;
+               break;
+       default:
+               return -ENODEV;
+       }
+       data->sio = sio;
+
+       platform_set_drvdata(pdev, data);
+
+       /* For each GPIO bank, register a GPIO chip. */
+       for (i = 0; i < data->nr_bank; i++) {
+               struct f7188x_gpio_bank *bank = &data->bank[i];
+
+               bank->chip.dev = &pdev->dev;
+               bank->data = data;
+
+               err = gpiochip_add(&bank->chip);
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "Failed to register gpiochip %d: %d\n",
+                               i, err);
+                       goto err_gpiochip;
+               }
+       }
+
+       return 0;
+
+err_gpiochip:
+       for (i = i - 1; i >= 0; i--) {
+               struct f7188x_gpio_bank *bank = &data->bank[i];
+               int tmp;
+
+               tmp = gpiochip_remove(&bank->chip);
+               if (tmp < 0)
+                       dev_err(&pdev->dev,
+                               "Failed to remove gpiochip %d: %d\n",
+                               i, tmp);
+       }
+
+       return err;
+}
+
+static int f7188x_gpio_remove(struct platform_device *pdev)
+{
+       int err;
+       int i;
+       struct f7188x_gpio_data *data = platform_get_drvdata(pdev);
+
+       for (i = 0; i < data->nr_bank; i++) {
+               struct f7188x_gpio_bank *bank = &data->bank[i];
+
+               err = gpiochip_remove(&bank->chip);
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "Failed to remove GPIO gpiochip %d: %d\n",
+                               i, err);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static int __init f7188x_find(int addr, struct f7188x_sio *sio)
+{
+       int err;
+       u16 devid;
+
+       err = superio_enter(addr);
+       if (err)
+               return err;
+
+       err = -ENODEV;
+       devid = superio_inw(addr, SIO_MANID);
+       if (devid != SIO_FINTEK_ID) {
+               pr_debug(DRVNAME ": Not a Fintek device at 0x%08x\n", addr);
+               goto err;
+       }
+
+       devid = superio_inw(addr, SIO_DEVID);
+       switch (devid) {
+       case SIO_F71882_ID:
+               sio->type = f71882fg;
+               break;
+       case SIO_F71889_ID:
+               sio->type = f71889f;
+               break;
+       default:
+               pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid);
+               goto err;
+       }
+       sio->addr = addr;
+       err = 0;
+
+       pr_info(DRVNAME ": Found %s at %#x, revision %d\n",
+               f7188x_names[sio->type],
+               (unsigned int) addr,
+               (int) superio_inb(addr, SIO_DEVREV));
+
+err:
+       superio_exit(addr);
+       return err;
+}
+
+static struct platform_device *f7188x_gpio_pdev;
+
+static int __init
+f7188x_gpio_device_add(const struct f7188x_sio *sio)
+{
+       int err;
+
+       f7188x_gpio_pdev = platform_device_alloc(DRVNAME, -1);
+       if (!f7188x_gpio_pdev)
+               return -ENOMEM;
+
+       err = platform_device_add_data(f7188x_gpio_pdev,
+                                      sio, sizeof(*sio));
+       if (err) {
+               pr_err(DRVNAME "Platform data allocation failed\n");
+               goto err;
+       }
+
+       err = platform_device_add(f7188x_gpio_pdev);
+       if (err) {
+               pr_err(DRVNAME "Device addition failed\n");
+               goto err;
+       }
+
+       return 0;
+
+err:
+       platform_device_put(f7188x_gpio_pdev);
+
+       return err;
+}
+
+/*
+ * Try to match a supported Fintech device by reading the (hard-wired)
+ * configuration I/O ports. If available, then register both the platform
+ * device and driver to support the GPIOs.
+ */
+
+static struct platform_driver f7188x_gpio_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = DRVNAME,
+       },
+       .probe          = f7188x_gpio_probe,
+       .remove         = f7188x_gpio_remove,
+};
+
+static int __init f7188x_gpio_init(void)
+{
+       int err;
+       struct f7188x_sio sio;
+
+       if (f7188x_find(0x2e, &sio) &&
+           f7188x_find(0x4e, &sio))
+               return -ENODEV;
+
+       err = platform_driver_register(&f7188x_gpio_driver);
+       if (!err) {
+               err = f7188x_gpio_device_add(&sio);
+               if (err)
+                       platform_driver_unregister(&f7188x_gpio_driver);
+       }
+
+       return err;
+}
+subsys_initcall(f7188x_gpio_init);
+
+static void __exit f7188x_gpio_exit(void)
+{
+       platform_device_unregister(f7188x_gpio_pdev);
+       platform_driver_unregister(&f7188x_gpio_driver);
+}
+module_exit(f7188x_gpio_exit);
+
+MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71882FG and F71889F");
+MODULE_AUTHOR("Simon Guinot <simon.guinot@sequanux.org>");
+MODULE_LICENSE("GPL");
index 2729e3d2d5bbe9da7781be8cf8de34be26d19535..814addb62d2cce372ac4a9df25733d6f3f52284e 100644 (file)
@@ -354,7 +354,7 @@ static int ichx_gpio_probe(struct platform_device *pdev)
 {
        struct resource *res_base, *res_pm;
        int err;
-       struct lpc_ich_info *ich_info = pdev->dev.platform_data;
+       struct lpc_ich_info *ich_info = dev_get_platdata(&pdev->dev);
 
        if (!ich_info)
                return -ENODEV;
index 7d0a04169a351ba54b0b53b67a0d587063da5bd7..2ecd3a09c743e6dba7434c9cbfab0e5c70bc24c3 100644 (file)
@@ -149,7 +149,7 @@ static int ttl_probe(struct platform_device *pdev)
        struct resource *res;
        int ret;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (!pdata) {
                dev_err(dev, "no platform data\n");
                ret = -ENXIO;
diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c
new file mode 100644 (file)
index 0000000..efdc392
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Kontron PLD GPIO driver
+ *
+ * Copyright (c) 2010-2013 Kontron Europe GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/kempld.h>
+
+#define KEMPLD_GPIO_MAX_NUM            16
+#define KEMPLD_GPIO_MASK(x)            (1 << ((x) % 8))
+#define KEMPLD_GPIO_DIR_NUM(x)         (0x40 + (x) / 8)
+#define KEMPLD_GPIO_LVL_NUM(x)         (0x42 + (x) / 8)
+#define KEMPLD_GPIO_EVT_LVL_EDGE       0x46
+#define KEMPLD_GPIO_IEN                        0x4A
+
+struct kempld_gpio_data {
+       struct gpio_chip                chip;
+       struct kempld_device_data       *pld;
+};
+
+/*
+ * Set or clear GPIO bit
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+static void kempld_gpio_bitop(struct kempld_device_data *pld,
+                             u8 reg, u8 bit, u8 val)
+{
+       u8 status;
+
+       status = kempld_read8(pld, reg);
+       if (val)
+               status |= KEMPLD_GPIO_MASK(bit);
+       else
+               status &= ~KEMPLD_GPIO_MASK(bit);
+       kempld_write8(pld, reg, status);
+}
+
+static int kempld_gpio_get_bit(struct kempld_device_data *pld, u8 reg, u8 bit)
+{
+       u8 status;
+
+       kempld_get_mutex(pld);
+       status = kempld_read8(pld, reg);
+       kempld_release_mutex(pld);
+
+       return !!(status & KEMPLD_GPIO_MASK(bit));
+}
+
+static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct kempld_gpio_data *gpio
+               = container_of(chip, struct kempld_gpio_data, chip);
+       struct kempld_device_data *pld = gpio->pld;
+
+       return kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset);
+}
+
+static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct kempld_gpio_data *gpio
+               = container_of(chip, struct kempld_gpio_data, chip);
+       struct kempld_device_data *pld = gpio->pld;
+
+       kempld_get_mutex(pld);
+       kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value);
+       kempld_release_mutex(pld);
+}
+
+static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct kempld_gpio_data *gpio
+               = container_of(chip, struct kempld_gpio_data, chip);
+       struct kempld_device_data *pld = gpio->pld;
+
+       kempld_get_mutex(pld);
+       kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 0);
+       kempld_release_mutex(pld);
+
+       return 0;
+}
+
+static int kempld_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+                                       int value)
+{
+       struct kempld_gpio_data *gpio
+               = container_of(chip, struct kempld_gpio_data, chip);
+       struct kempld_device_data *pld = gpio->pld;
+
+       kempld_get_mutex(pld);
+       kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value);
+       kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 1);
+       kempld_release_mutex(pld);
+
+       return 0;
+}
+
+static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+       struct kempld_gpio_data *gpio
+               = container_of(chip, struct kempld_gpio_data, chip);
+       struct kempld_device_data *pld = gpio->pld;
+
+       return kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset);
+}
+
+static int kempld_gpio_pincount(struct kempld_device_data *pld)
+{
+       u16 evt, evt_back;
+
+       kempld_get_mutex(pld);
+
+       /* Backup event register as it might be already initialized */
+       evt_back = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE);
+       /* Clear event register */
+       kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, 0x0000);
+       /* Read back event register */
+       evt = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE);
+       /* Restore event register */
+       kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, evt_back);
+
+       kempld_release_mutex(pld);
+
+       return evt ? __ffs(evt) : 16;
+}
+
+static int kempld_gpio_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct kempld_device_data *pld = dev_get_drvdata(dev->parent);
+       struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
+       struct kempld_gpio_data *gpio;
+       struct gpio_chip *chip;
+       int ret;
+
+       if (pld->info.spec_major < 2) {
+               dev_err(dev,
+                       "Driver only supports GPIO devices compatible to PLD spec. rev. 2.0 or higher\n");
+               return -ENODEV;
+       }
+
+       gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
+       if (gpio == NULL)
+               return -ENOMEM;
+
+       gpio->pld = pld;
+
+       platform_set_drvdata(pdev, gpio);
+
+       chip = &gpio->chip;
+       chip->label = "gpio-kempld";
+       chip->owner = THIS_MODULE;
+       chip->dev = dev;
+       chip->can_sleep = 1;
+       if (pdata && pdata->gpio_base)
+               chip->base = pdata->gpio_base;
+       else
+               chip->base = -1;
+       chip->direction_input = kempld_gpio_direction_input;
+       chip->direction_output = kempld_gpio_direction_output;
+       chip->get_direction = kempld_gpio_get_direction;
+       chip->get = kempld_gpio_get;
+       chip->set = kempld_gpio_set;
+       chip->ngpio = kempld_gpio_pincount(pld);
+       if (chip->ngpio == 0) {
+               dev_err(dev, "No GPIO pins detected\n");
+               return -ENODEV;
+       }
+
+       ret = gpiochip_add(chip);
+       if (ret) {
+               dev_err(dev, "Could not register GPIO chip\n");
+               return ret;
+       }
+
+       dev_info(dev, "GPIO functionality initialized with %d pins\n",
+                chip->ngpio);
+
+       return 0;
+}
+
+static int kempld_gpio_remove(struct platform_device *pdev)
+{
+       struct kempld_gpio_data *gpio = platform_get_drvdata(pdev);
+
+       return gpiochip_remove(&gpio->chip);
+}
+
+static struct platform_driver kempld_gpio_driver = {
+       .driver = {
+               .name = "kempld-gpio",
+               .owner = THIS_MODULE,
+       },
+       .probe          = kempld_gpio_probe,
+       .remove         = kempld_gpio_remove,
+};
+
+module_platform_driver(kempld_gpio_driver);
+
+MODULE_DESCRIPTION("KEM PLD GPIO Driver");
+MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-kempld");
index 761c4705dfbb357b437f263dac54d1a5c8272864..41b5913ddabe6e0a8b1f417004d86628234b77c5 100644 (file)
@@ -248,14 +248,15 @@ static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
        struct lp_gpio *lg = irq_data_get_irq_handler_data(data);
        struct irq_chip *chip = irq_data_get_irq_chip(data);
        u32 base, pin, mask;
-       unsigned long reg, pending;
+       unsigned long reg, ena, pending;
        unsigned virq;
 
        /* check from GPIO controller which pin triggered the interrupt */
        for (base = 0; base < lg->chip.ngpio; base += 32) {
                reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
+               ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
 
-               while ((pending = inl(reg))) {
+               while ((pending = (inl(reg) & inl(ena)))) {
                        pin = __ffs(pending);
                        mask = BIT(pin);
                        /* Clear before handling so we don't lose an edge */
@@ -444,6 +445,7 @@ static int lp_gpio_remove(struct platform_device *pdev)
 {
        struct lp_gpio *lg = platform_get_drvdata(pdev);
        int err;
+       pm_runtime_disable(&pdev->dev);
        err = gpiochip_remove(&lg->chip);
        if (err)
                dev_warn(&pdev->dev, "failed to remove gpio_chip.\n");
index 3b16ab7016301f0ff27cb2b05b070b377918d986..6e1c984a75d45e4253d0f2c1563364d310f37708 100644 (file)
@@ -56,8 +56,7 @@ static int max7301_probe(struct spi_device *spi)
        int ret;
 
        /* bits_per_word cannot be configured in platform data */
-       if (spi->dev.platform_data)
-               spi->bits_per_word = 16;
+       spi->bits_per_word = 16;
        ret = spi_setup(spi);
        if (ret < 0)
                return ret;
index 00092342b84c050d0c1d0e32b9202919108aa11a..f4f4ed19bdc13c8211d1eb74244afab51088738f 100644 (file)
@@ -166,7 +166,7 @@ int __max730x_probe(struct max7301 *ts)
        struct max7301_platform_data *pdata;
        int i, ret;
 
-       pdata = dev->platform_data;
+       pdata = dev_get_platdata(dev);
 
        mutex_init(&ts->lock);
        dev_set_drvdata(dev, ts);
index d4b51b163b039f9aa6ed93c007a3d0d56160f3e1..91ad74dea8ceab68dc6048ce10a1b14e6ccaf80e 100644 (file)
@@ -453,7 +453,7 @@ static int max732x_irq_setup(struct max732x_chip *chip,
                             const struct i2c_device_id *id)
 {
        struct i2c_client *client = chip->client;
-       struct max732x_platform_data *pdata = client->dev.platform_data;
+       struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
        int has_irq = max732x_features[id->driver_data] >> 32;
        int ret;
 
@@ -512,7 +512,7 @@ static int max732x_irq_setup(struct max732x_chip *chip,
                             const struct i2c_device_id *id)
 {
        struct i2c_client *client = chip->client;
-       struct max732x_platform_data *pdata = client->dev.platform_data;
+       struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
        int has_irq = max732x_features[id->driver_data] >> 32;
 
        if (pdata->irq_base && has_irq != INT_NONE)
@@ -583,7 +583,7 @@ static int max732x_probe(struct i2c_client *client,
        uint16_t addr_a, addr_b;
        int ret, nr_port;
 
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
        if (pdata == NULL) {
                dev_dbg(&client->dev, "no platform data\n");
                return -EINVAL;
@@ -653,7 +653,7 @@ out_failed:
 
 static int max732x_remove(struct i2c_client *client)
 {
-       struct max732x_platform_data *pdata = client->dev.platform_data;
+       struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
        struct max732x_chip *chip = i2c_get_clientdata(client);
        int ret;
 
index 63a7a1bfb2d90a675473015c20591289a61465c1..3fd2caa4a2e02fd05a71022a522c51add55f5e66 100644 (file)
@@ -86,7 +86,7 @@ static int mc33880_probe(struct spi_device *spi)
        struct mc33880_platform_data *pdata;
        int ret;
 
-       pdata = spi->dev.platform_data;
+       pdata = dev_get_platdata(&spi->dev);
        if (!pdata || !pdata->base) {
                dev_dbg(&spi->dev, "incorrect or missing platform data\n");
                return -EINVAL;
index 6a4470b84488eca7907ce509d7d77fcf3f0ff5fb..2deb0c5e54a443a7546c7e4c63bf1e6a833c0d50 100644 (file)
@@ -483,10 +483,21 @@ fail:
 #ifdef CONFIG_SPI_MASTER
 static struct of_device_id mcp23s08_spi_of_match[] = {
        {
-               .compatible = "mcp,mcp23s08", .data = (void *) MCP_TYPE_S08,
+               .compatible = "microchip,mcp23s08",
+               .data = (void *) MCP_TYPE_S08,
        },
        {
-               .compatible = "mcp,mcp23s17", .data = (void *) MCP_TYPE_S17,
+               .compatible = "microchip,mcp23s17",
+               .data = (void *) MCP_TYPE_S17,
+       },
+/* NOTE: The use of the mcp prefix is deprecated and will be removed. */
+       {
+               .compatible = "mcp,mcp23s08",
+               .data = (void *) MCP_TYPE_S08,
+       },
+       {
+               .compatible = "mcp,mcp23s17",
+               .data = (void *) MCP_TYPE_S17,
        },
        { },
 };
@@ -496,10 +507,21 @@ MODULE_DEVICE_TABLE(of, mcp23s08_spi_of_match);
 #if IS_ENABLED(CONFIG_I2C)
 static struct of_device_id mcp23s08_i2c_of_match[] = {
        {
-               .compatible = "mcp,mcp23008", .data = (void *) MCP_TYPE_008,
+               .compatible = "microchip,mcp23008",
+               .data = (void *) MCP_TYPE_008,
+       },
+       {
+               .compatible = "microchip,mcp23017",
+               .data = (void *) MCP_TYPE_017,
+       },
+/* NOTE: The use of the mcp prefix is deprecated and will be removed. */
+       {
+               .compatible = "mcp,mcp23008",
+               .data = (void *) MCP_TYPE_008,
        },
        {
-               .compatible = "mcp,mcp23017", .data = (void *) MCP_TYPE_017,
+               .compatible = "mcp,mcp23017",
+               .data = (void *) MCP_TYPE_017,
        },
        { },
 };
@@ -520,14 +542,13 @@ static int mcp230xx_probe(struct i2c_client *client,
 
        match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match),
                                        &client->dev);
-       if (match) {
+       pdata = dev_get_platdata(&client->dev);
+       if (match || !pdata) {
                base = -1;
                pullups = 0;
        } else {
-               pdata = client->dev.platform_data;
-               if (!pdata || !gpio_is_valid(pdata->base)) {
-                       dev_dbg(&client->dev,
-                                       "invalid or missing platform data\n");
+               if (!gpio_is_valid(pdata->base)) {
+                       dev_dbg(&client->dev, "invalid platform data\n");
                        return -EINVAL;
                }
                base = pdata->base;
@@ -621,10 +642,15 @@ static int mcp23s08_probe(struct spi_device *spi)
        if (match) {
                type = (int)match->data;
                status = of_property_read_u32(spi->dev.of_node,
-                               "mcp,spi-present-mask", &spi_present_mask);
+                           "microchip,spi-present-mask", &spi_present_mask);
                if (status) {
-                       dev_err(&spi->dev, "DT has no spi-present-mask\n");
-                       return -ENODEV;
+                       status = of_property_read_u32(spi->dev.of_node,
+                                   "mcp,spi-present-mask", &spi_present_mask);
+                       if (status) {
+                               dev_err(&spi->dev,
+                                       "DT has no spi-present-mask\n");
+                               return -ENODEV;
+                       }
                }
                if ((spi_present_mask <= 0) || (spi_present_mask >= 256)) {
                        dev_err(&spi->dev, "invalid spi-present-mask\n");
@@ -635,7 +661,7 @@ static int mcp23s08_probe(struct spi_device *spi)
                        pullups[addr] = 0;
        } else {
                type = spi_get_device_id(spi)->driver_data;
-               pdata = spi->dev.platform_data;
+               pdata = dev_get_platdata(&spi->dev);
                if (!pdata || !gpio_is_valid(pdata->base)) {
                        dev_dbg(&spi->dev,
                                        "invalid or missing platform data\n");
index 27ea7b9257ff7ce0eb25ff765e275b36c3a1372f..d75eaa3a1dcc5f2e158ff4bdf59c991402a3b822 100644 (file)
@@ -259,7 +259,7 @@ static void msic_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 static int platform_msic_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct intel_msic_gpio_pdata *pdata = dev->platform_data;
+       struct intel_msic_gpio_pdata *pdata = dev_get_platdata(dev);
        struct msic_gpio *mg;
        int irq = platform_get_irq(pdev, 0);
        int retval;
index c2fa77086eb58cf9de7f2c2a453c900a9771f0b5..f7a0cc4da9502d12ef0aa602dfa249665e5a5c4a 100644 (file)
@@ -106,7 +106,7 @@ struct msm_gpio_dev {
        void __iomem *msm_tlmm_base;
 };
 
-struct msm_gpio_dev msm_gpio;
+static struct msm_gpio_dev msm_gpio;
 
 #define GPIO_INTR_CFG_SU(gpio)    (msm_gpio.msm_tlmm_base + 0x0400 + \
                                                                (0x04 * (gpio)))
index 80ad35e2a8cd5ac3af9f39f0cba644c7062fb592..3c3321f94053ab68f0ab0e691afc1ddf2b83f0e9 100644 (file)
@@ -566,12 +566,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
        else
                soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Cannot get memory resource\n");
-               return -ENODEV;
-       }
-
        mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL);
        if (!mvchip) {
                dev_err(&pdev->dev, "Cannot allocate memory\n");
@@ -611,6 +605,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
        mvchip->chip.dbg_show = mvebu_gpio_dbg_show;
 
        spin_lock_init(&mvchip->lock);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        mvchip->membase = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(mvchip->membase))
                return PTR_ERR(mvchip->membase);
index 7176743915d3df032cefa2ec33a327f7b22f799b..3307f6db3a925fb3469c29f34eb69bfb93ca312a 100644 (file)
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -291,6 +292,9 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc)
 {
        u32 irq_msk, irq_stat;
        struct mxc_gpio_port *port;
+       struct irq_chip *chip = irq_get_chip(irq);
+
+       chained_irq_enter(chip, desc);
 
        /* walk through all interrupt status registers */
        list_for_each_entry(port, &mxc_gpio_ports, node) {
@@ -302,6 +306,7 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc)
                if (irq_stat)
                        mxc_gpio_irq_handler(port, irq_stat);
        }
+       chained_irq_exit(chip, desc);
 }
 
 /*
@@ -405,34 +410,19 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 
        mxc_gpio_get_hw(pdev);
 
-       port = kzalloc(sizeof(struct mxc_gpio_port), GFP_KERNEL);
+       port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
        if (!port)
                return -ENOMEM;
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iores) {
-               err = -ENODEV;
-               goto out_kfree;
-       }
-
-       if (!request_mem_region(iores->start, resource_size(iores),
-                               pdev->name)) {
-               err = -EBUSY;
-               goto out_kfree;
-       }
-
-       port->base = ioremap(iores->start, resource_size(iores));
-       if (!port->base) {
-               err = -ENOMEM;
-               goto out_release_mem;
-       }
+       port->base = devm_ioremap_resource(&pdev->dev, iores);
+       if (IS_ERR(port->base))
+               return PTR_ERR(port->base);
 
        port->irq_high = platform_get_irq(pdev, 1);
        port->irq = platform_get_irq(pdev, 0);
-       if (port->irq < 0) {
-               err = -EINVAL;
-               goto out_iounmap;
-       }
+       if (port->irq < 0)
+               return -EINVAL;
 
        /* disable the interrupt and clear the status */
        writel(0, port->base + GPIO_IMR);
@@ -462,7 +452,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
                         port->base + GPIO_DR, NULL,
                         port->base + GPIO_GDIR, NULL, 0);
        if (err)
-               goto out_iounmap;
+               goto out_bgio;
 
        port->bgc.gc.to_irq = mxc_gpio_to_irq;
        port->bgc.gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
@@ -498,12 +488,7 @@ out_gpiochip_remove:
        WARN_ON(gpiochip_remove(&port->bgc.gc) < 0);
 out_bgpio_remove:
        bgpio_remove(&port->bgc);
-out_iounmap:
-       iounmap(port->base);
-out_release_mem:
-       release_mem_region(iores->start, resource_size(iores));
-out_kfree:
-       kfree(port);
+out_bgio:
        dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err);
        return err;
 }
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 dfeb3a3a8f20949098b5dc0e703ffe1ea944f245..89675f862308f95d41d962c3faae99b80a458869 100644 (file)
@@ -63,6 +63,7 @@ struct gpio_bank {
        struct gpio_chip chip;
        struct clk *dbck;
        u32 mod_usage;
+       u32 irq_usage;
        u32 dbck_enable_mask;
        bool dbck_enabled;
        struct device *dev;
@@ -86,6 +87,9 @@ struct gpio_bank {
 #define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio))
 #define GPIO_MOD_CTRL_BIT      BIT(0)
 
+#define BANK_USED(bank) (bank->mod_usage || bank->irq_usage)
+#define LINE_USED(line, offset) (line & (1 << offset))
+
 static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
 {
        return bank->chip.base + gpio_irq;
@@ -420,15 +424,69 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
        return 0;
 }
 
+static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset)
+{
+       if (bank->regs->pinctrl) {
+               void __iomem *reg = bank->base + bank->regs->pinctrl;
+
+               /* Claim the pin for MPU */
+               __raw_writel(__raw_readl(reg) | (1 << offset), reg);
+       }
+
+       if (bank->regs->ctrl && !BANK_USED(bank)) {
+               void __iomem *reg = bank->base + bank->regs->ctrl;
+               u32 ctrl;
+
+               ctrl = __raw_readl(reg);
+               /* Module is enabled, clocks are not gated */
+               ctrl &= ~GPIO_MOD_CTRL_BIT;
+               __raw_writel(ctrl, reg);
+               bank->context.ctrl = ctrl;
+       }
+}
+
+static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset)
+{
+       void __iomem *base = bank->base;
+
+       if (bank->regs->wkup_en &&
+           !LINE_USED(bank->mod_usage, offset) &&
+           !LINE_USED(bank->irq_usage, offset)) {
+               /* Disable wake-up during idle for dynamic tick */
+               _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0);
+               bank->context.wake_en =
+                       __raw_readl(bank->base + bank->regs->wkup_en);
+       }
+
+       if (bank->regs->ctrl && !BANK_USED(bank)) {
+               void __iomem *reg = bank->base + bank->regs->ctrl;
+               u32 ctrl;
+
+               ctrl = __raw_readl(reg);
+               /* Module is disabled, clocks are gated */
+               ctrl |= GPIO_MOD_CTRL_BIT;
+               __raw_writel(ctrl, reg);
+               bank->context.ctrl = ctrl;
+       }
+}
+
+static int gpio_is_input(struct gpio_bank *bank, int mask)
+{
+       void __iomem *reg = bank->base + bank->regs->direction;
+
+       return __raw_readl(reg) & mask;
+}
+
 static int gpio_irq_type(struct irq_data *d, unsigned type)
 {
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
        unsigned gpio = 0;
        int retval;
        unsigned long flags;
+       unsigned offset;
 
-       if (WARN_ON(!bank->mod_usage))
-               return -EINVAL;
+       if (!BANK_USED(bank))
+               pm_runtime_get_sync(bank->dev);
 
 #ifdef CONFIG_ARCH_OMAP1
        if (d->irq > IH_MPUIO_BASE)
@@ -446,7 +504,17 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
                return -EINVAL;
 
        spin_lock_irqsave(&bank->lock, flags);
-       retval = _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), type);
+       offset = GPIO_INDEX(bank, gpio);
+       retval = _set_gpio_triggering(bank, offset, type);
+       if (!LINE_USED(bank->mod_usage, offset)) {
+               _enable_gpio_module(bank, offset);
+               _set_gpio_direction(bank, offset, 1);
+       } else if (!gpio_is_input(bank, 1 << offset)) {
+               spin_unlock_irqrestore(&bank->lock, flags);
+               return -EINVAL;
+       }
+
+       bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio);
        spin_unlock_irqrestore(&bank->lock, flags);
 
        if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
@@ -603,35 +671,19 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
         * If this is the first gpio_request for the bank,
         * enable the bank module.
         */
-       if (!bank->mod_usage)
+       if (!BANK_USED(bank))
                pm_runtime_get_sync(bank->dev);
 
        spin_lock_irqsave(&bank->lock, flags);
        /* Set trigger to none. You need to enable the desired trigger with
-        * request_irq() or set_irq_type().
+        * request_irq() or set_irq_type(). Only do this if the IRQ line has
+        * not already been requested.
         */
-       _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
-
-       if (bank->regs->pinctrl) {
-               void __iomem *reg = bank->base + bank->regs->pinctrl;
-
-               /* Claim the pin for MPU */
-               __raw_writel(__raw_readl(reg) | (1 << offset), reg);
-       }
-
-       if (bank->regs->ctrl && !bank->mod_usage) {
-               void __iomem *reg = bank->base + bank->regs->ctrl;
-               u32 ctrl;
-
-               ctrl = __raw_readl(reg);
-               /* Module is enabled, clocks are not gated */
-               ctrl &= ~GPIO_MOD_CTRL_BIT;
-               __raw_writel(ctrl, reg);
-               bank->context.ctrl = ctrl;
+       if (!LINE_USED(bank->irq_usage, offset)) {
+               _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+               _enable_gpio_module(bank, offset);
        }
-
        bank->mod_usage |= 1 << offset;
-
        spin_unlock_irqrestore(&bank->lock, flags);
 
        return 0;
@@ -640,31 +692,11 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
        struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
-       void __iomem *base = bank->base;
        unsigned long flags;
 
        spin_lock_irqsave(&bank->lock, flags);
-
-       if (bank->regs->wkup_en) {
-               /* Disable wake-up during idle for dynamic tick */
-               _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0);
-               bank->context.wake_en =
-                       __raw_readl(bank->base + bank->regs->wkup_en);
-       }
-
        bank->mod_usage &= ~(1 << offset);
-
-       if (bank->regs->ctrl && !bank->mod_usage) {
-               void __iomem *reg = bank->base + bank->regs->ctrl;
-               u32 ctrl;
-
-               ctrl = __raw_readl(reg);
-               /* Module is disabled, clocks are gated */
-               ctrl |= GPIO_MOD_CTRL_BIT;
-               __raw_writel(ctrl, reg);
-               bank->context.ctrl = ctrl;
-       }
-
+       _disable_gpio_module(bank, offset);
        _reset_gpio(bank, bank->chip.base + offset);
        spin_unlock_irqrestore(&bank->lock, flags);
 
@@ -672,7 +704,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
         * If this is the last gpio to be freed in the bank,
         * disable the bank module.
         */
-       if (!bank->mod_usage)
+       if (!BANK_USED(bank))
                pm_runtime_put(bank->dev);
 }
 
@@ -762,10 +794,20 @@ static void gpio_irq_shutdown(struct irq_data *d)
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
        unsigned int gpio = irq_to_gpio(bank, d->hwirq);
        unsigned long flags;
+       unsigned offset = GPIO_INDEX(bank, gpio);
 
        spin_lock_irqsave(&bank->lock, flags);
+       bank->irq_usage &= ~(1 << offset);
+       _disable_gpio_module(bank, offset);
        _reset_gpio(bank, gpio);
        spin_unlock_irqrestore(&bank->lock, flags);
+
+       /*
+        * If this is the last IRQ to be freed in the bank,
+        * disable the bank module.
+        */
+       if (!BANK_USED(bank))
+               pm_runtime_put(bank->dev);
 }
 
 static void gpio_ack_irq(struct irq_data *d)
@@ -897,13 +939,6 @@ static int gpio_input(struct gpio_chip *chip, unsigned offset)
        return 0;
 }
 
-static int gpio_is_input(struct gpio_bank *bank, int mask)
-{
-       void __iomem *reg = bank->base + bank->regs->direction;
-
-       return __raw_readl(reg) & mask;
-}
-
 static int gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct gpio_bank *bank;
@@ -922,13 +957,22 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct gpio_bank *bank;
        unsigned long flags;
+       int retval = 0;
 
        bank = container_of(chip, struct gpio_bank, chip);
        spin_lock_irqsave(&bank->lock, flags);
+
+       if (LINE_USED(bank->irq_usage, offset)) {
+                       retval = -EINVAL;
+                       goto exit;
+       }
+
        bank->set_dataout(bank, offset, value);
        _set_gpio_direction(bank, offset, 0);
+
+exit:
        spin_unlock_irqrestore(&bank->lock, flags);
-       return 0;
+       return retval;
 }
 
 static int gpio_debounce(struct gpio_chip *chip, unsigned offset,
@@ -1030,7 +1074,7 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
        ct->chip.irq_set_type = gpio_irq_type;
 
        if (bank->regs->wkup_en)
-               ct->chip.irq_set_wake = gpio_wake_enable,
+               ct->chip.irq_set_wake = gpio_wake_enable;
 
        ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride;
        irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
@@ -1100,7 +1144,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
 
        match = of_match_device(of_match_ptr(omap_gpio_match), dev);
 
-       pdata = match ? match->data : dev->platform_data;
+       pdata = match ? match->data : dev_get_platdata(dev);
        if (!pdata)
                return -EINVAL;
 
@@ -1400,7 +1444,7 @@ void omap2_gpio_prepare_for_idle(int pwr_mode)
        struct gpio_bank *bank;
 
        list_for_each_entry(bank, &omap_gpio_list, node) {
-               if (!bank->mod_usage || !bank->loses_context)
+               if (!BANK_USED(bank) || !bank->loses_context)
                        continue;
 
                bank->power_mode = pwr_mode;
@@ -1414,7 +1458,7 @@ void omap2_gpio_resume_after_idle(void)
        struct gpio_bank *bank;
 
        list_for_each_entry(bank, &omap_gpio_list, node) {
-               if (!bank->mod_usage || !bank->loses_context)
+               if (!BANK_USED(bank) || !bank->loses_context)
                        continue;
 
                pm_runtime_get_sync(bank->dev);
index e3a4e56f5a4233d4754449fcd342b4b41c9d623f..8588af0f766126076ef61ff50d58dac120af7ee4 100644 (file)
@@ -43,9 +43,22 @@ static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
        unsigned int val;
        int ret;
 
-       ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_IN, &val);
+       ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_DIR, &val);
        if (ret < 0) {
-               dev_err(gc->dev, "GPIO_DATA_IN read failed, err = %d\n", ret);
+               dev_err(gc->dev, "GPIO_DATA_DIR read failed, err = %d\n", ret);
+               return ret;
+       }
+
+       if (val & (1 << offset)) {
+               ret = palmas_read(palmas, PALMAS_GPIO_BASE,
+                                 PALMAS_GPIO_DATA_OUT, &val);
+       } else {
+               ret = palmas_read(palmas, PALMAS_GPIO_BASE,
+                                 PALMAS_GPIO_DATA_IN, &val);
+       }
+       if (ret < 0) {
+               dev_err(gc->dev, "GPIO_DATA_IN/OUT read failed, err = %d\n",
+                       ret);
                return ret;
        }
        return !!(val & BIT(offset));
@@ -134,7 +147,7 @@ static int palmas_gpio_probe(struct platform_device *pdev)
        palmas_gpio->gpio_chip.get      = palmas_gpio_get;
        palmas_gpio->gpio_chip.dev = &pdev->dev;
 #ifdef CONFIG_OF_GPIO
-       palmas_gpio->gpio_chip.of_node = palmas->dev->of_node;
+       palmas_gpio->gpio_chip.of_node = pdev->dev.of_node;
 #endif
        palmas_pdata = dev_get_platdata(palmas->dev);
        if (palmas_pdata && palmas_pdata->gpio_base)
@@ -159,9 +172,19 @@ static int palmas_gpio_remove(struct platform_device *pdev)
        return gpiochip_remove(&palmas_gpio->gpio_chip);
 }
 
+static struct of_device_id of_palmas_gpio_match[] = {
+       { .compatible = "ti,palmas-gpio"},
+       { .compatible = "ti,tps65913-gpio"},
+       { .compatible = "ti,tps65914-gpio"},
+       { .compatible = "ti,tps80036-gpio"},
+       { },
+};
+MODULE_DEVICE_TABLE(of, of_palmas_gpio_match);
+
 static struct platform_driver palmas_gpio_driver = {
        .driver.name    = "palmas-gpio",
        .driver.owner   = THIS_MODULE,
+       .driver.of_match_table = of_palmas_gpio_match,
        .probe          = palmas_gpio_probe,
        .remove         = palmas_gpio_remove,
 };
index 8804aec2950fb9f81e317f4b7e46bd2a2d601aaf..cdd1aa12b895e3017bfd79da95e6b499fb3bf28f 100644 (file)
@@ -308,7 +308,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
                return 0;
        }
 
-       return (reg_val & (1u << off)) ? 1 : 0;
+       return (reg_val & (1u << (off % BANK_SZ))) ? 1 : 0;
 }
 
 static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
@@ -731,7 +731,7 @@ static int pca953x_probe(struct i2c_client *client,
        if (chip == NULL)
                return -ENOMEM;
 
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
        if (pdata) {
                irq_base = pdata->irq_base;
                chip->gpio_start = pdata->gpio_base;
@@ -785,7 +785,7 @@ static int pca953x_probe(struct i2c_client *client,
 
 static int pca953x_remove(struct i2c_client *client)
 {
-       struct pca953x_platform_data *pdata = client->dev.platform_data;
+       struct pca953x_platform_data *pdata = dev_get_platdata(&client->dev);
        struct pca953x_chip *chip = i2c_get_clientdata(client);
        int ret = 0;
 
index e8faf53f3875df488eaba35c7463de6a3f03bd29..9e61bb0719d0cac80f176b941adf51aa52cd9b01 100644 (file)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/kernel.h>
-#include <linux/slab.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/i2c/pcf857x.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
 
@@ -223,7 +223,6 @@ static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio)
 }
 
 static int pcf857x_irq_domain_init(struct pcf857x *gpio,
-                                  struct pcf857x_platform_data *pdata,
                                   struct i2c_client *client)
 {
        int status;
@@ -262,7 +261,7 @@ static int pcf857x_probe(struct i2c_client *client,
        struct pcf857x                  *gpio;
        int                             status;
 
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
        if (!pdata) {
                dev_dbg(&client->dev, "no platform data\n");
        }
@@ -286,8 +285,8 @@ static int pcf857x_probe(struct i2c_client *client,
        gpio->chip.ngpio                = id->driver_data;
 
        /* enable gpio_to_irq() if platform has settings */
-       if (pdata && client->irq) {
-               status = pcf857x_irq_domain_init(gpio, pdata, client);
+       if (client->irq) {
+               status = pcf857x_irq_domain_init(gpio, client);
                if (status < 0) {
                        dev_err(&client->dev, "irq_domain init failed\n");
                        goto fail;
@@ -388,7 +387,7 @@ fail:
        dev_dbg(&client->dev, "probe error %d for '%s'\n",
                        status, client->name);
 
-       if (pdata && client->irq)
+       if (client->irq)
                pcf857x_irq_domain_cleanup(gpio);
 
        return status;
@@ -396,7 +395,7 @@ fail:
 
 static int pcf857x_remove(struct i2c_client *client)
 {
-       struct pcf857x_platform_data    *pdata = client->dev.platform_data;
+       struct pcf857x_platform_data    *pdata = dev_get_platdata(&client->dev);
        struct pcf857x                  *gpio = i2c_get_clientdata(client);
        int                             status = 0;
 
@@ -411,7 +410,7 @@ static int pcf857x_remove(struct i2c_client *client)
                }
        }
 
-       if (pdata && client->irq)
+       if (client->irq)
                pcf857x_irq_domain_cleanup(gpio);
 
        status = gpiochip_remove(&gpio->chip);
index 6a4bd0dae0ceb9c3d2d6f7c020c273f0fb269618..4274e2e70ef8e8e31fcdb6da0370ae265f383190 100644 (file)
@@ -259,7 +259,7 @@ static const struct irq_domain_ops pl061_domain_ops = {
 static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 {
        struct device *dev = &adev->dev;
-       struct pl061_platform_data *pdata = dev->platform_data;
+       struct pl061_platform_data *pdata = dev_get_platdata(dev);
        struct pl061_gpio *chip;
        int ret, irq, i, irq_base;
 
index df2199dd149975e37a31efc6a881450a6ad6af12..cc13d1b74fad09f06c0d2bd42cc4d41b196df2cf 100644 (file)
@@ -524,8 +524,8 @@ const struct irq_domain_ops pxa_irq_domain_ops = {
 
 static int pxa_gpio_probe_dt(struct platform_device *pdev)
 {
-       int ret, nr_gpios;
-       struct device_node *prev, *next, *np = pdev->dev.of_node;
+       int ret = 0, nr_gpios;
+       struct device_node *np = pdev->dev.of_node;
        const struct of_device_id *of_id =
                                of_match_device(pxa_gpio_dt_ids, &pdev->dev);
        const struct pxa_gpio_id *gpio_id;
@@ -537,20 +537,13 @@ static int pxa_gpio_probe_dt(struct platform_device *pdev)
        gpio_id = of_id->data;
        gpio_type = gpio_id->type;
 
-       next = of_get_next_child(np, NULL);
-       prev = next;
-       if (!next) {
-               dev_err(&pdev->dev, "Failed to find child gpio node\n");
-               ret = -EINVAL;
-               goto err;
-       }
-       of_node_put(prev);
        nr_gpios = gpio_id->gpio_nums;
        pxa_last_gpio = nr_gpios - 1;
 
        irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0);
        if (irq_base < 0) {
                dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
+               ret = irq_base;
                goto err;
        }
        domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0,
index e8198dd686155da6487440a84d5a64e04c213317..6038966ab045529b071242424e49b12237db316a 100644 (file)
@@ -285,7 +285,7 @@ static struct irq_domain_ops gpio_rcar_irq_domain_ops = {
 
 static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p)
 {
-       struct gpio_rcar_config *pdata = p->pdev->dev.platform_data;
+       struct gpio_rcar_config *pdata = dev_get_platdata(&p->pdev->dev);
        struct device_node *np = p->pdev->dev.of_node;
        struct of_phandle_args args;
        int ret;
@@ -293,10 +293,9 @@ static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p)
        if (pdata) {
                p->config = *pdata;
        } else if (IS_ENABLED(CONFIG_OF) && np) {
-               ret = of_parse_phandle_with_args(np, "gpio-ranges",
-                               "#gpio-range-cells", 0, &args);
-               p->config.number_of_pins = ret == 0 && args.args_count == 3
-                                        ? args.args[2]
+               ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0,
+                                                      &args);
+               p->config.number_of_pins = ret == 0 ? args.args[2]
                                         : RCAR_MAX_GPIO_PER_BANK;
                p->config.gpio_base = -1;
        }
index 368c3c00fca5973fd02bcb5661af1546ded23e16..88577c3272a5536871f903e199aaf2a7bd37d3eb 100644 (file)
@@ -135,7 +135,7 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)
        struct rdc321x_gpio *rdc321x_gpio_dev;
        struct rdc321x_gpio_pdata *pdata;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data supplied\n");
                return -ENODEV;
index a1392f47bbda5b06b55f41035cf728b0e38d97a5..358a21c2d811bc6637960ed167ae8e95260ecfca 100644 (file)
@@ -161,28 +161,6 @@ int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip,
        return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN);
 }
 
-static int exynos_gpio_setpull(struct samsung_gpio_chip *chip,
-                               unsigned int off, samsung_gpio_pull_t pull)
-{
-       if (pull == S3C_GPIO_PULL_UP)
-               pull = 3;
-
-       return samsung_gpio_setpull_updown(chip, off, pull);
-}
-
-static samsung_gpio_pull_t exynos_gpio_getpull(struct samsung_gpio_chip *chip,
-                                               unsigned int off)
-{
-       samsung_gpio_pull_t pull;
-
-       pull = samsung_gpio_getpull_updown(chip, off);
-
-       if (pull == 3)
-               pull = S3C_GPIO_PULL_UP;
-
-       return pull;
-}
-
 /*
  * samsung_gpio_setcfg_2bit - Samsung 2bit style GPIO configuration.
  * @chip: The gpio chip that is being configured.
@@ -444,15 +422,6 @@ static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = {
 };
 #endif
 
-#if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_SOC_EXYNOS5250)
-static struct samsung_gpio_cfg exynos_gpio_cfg = {
-       .set_pull       = exynos_gpio_setpull,
-       .get_pull       = exynos_gpio_getpull,
-       .set_config     = samsung_gpio_setcfg_4bit,
-       .get_config     = samsung_gpio_getcfg_4bit,
-};
-#endif
-
 #if defined(CONFIG_CPU_S5P6440) || defined(CONFIG_CPU_S5P6450)
 static struct samsung_gpio_cfg s5p64x0_gpio_cfg_rbank = {
        .cfg_eint       = 0x3,
@@ -495,15 +464,6 @@ static struct samsung_gpio_cfg samsung_gpio_cfgs[] = {
                .set_config     = samsung_gpio_setcfg_2bit,
                .get_config     = samsung_gpio_getcfg_2bit,
        },
-       [8] = {
-               .set_pull       = exynos_gpio_setpull,
-               .get_pull       = exynos_gpio_getpull,
-       },
-       [9] = {
-               .cfg_eint       = 0x3,
-               .set_pull       = exynos_gpio_setpull,
-               .get_pull       = exynos_gpio_getpull,
-       }
 };
 
 /*
@@ -2115,833 +2075,6 @@ static struct samsung_gpio_chip s5pv210_gpios_4bit[] = {
 #endif
 };
 
-/*
- * Followings are the gpio banks in EXYNOS SoCs
- *
- * The 'config' member when left to NULL, is initialized to the default
- * structure exynos_gpio_cfg in the init function below.
- *
- * The 'base' member is also initialized in the init function below.
- * Note: The initialization of 'base' member of samsung_gpio_chip structure
- * uses the above macro and depends on the banks being listed in order here.
- */
-
-#ifdef CONFIG_ARCH_EXYNOS4
-static struct samsung_gpio_chip exynos4_gpios_1[] = {
-       {
-               .chip   = {
-                       .base   = EXYNOS4_GPA0(0),
-                       .ngpio  = EXYNOS4_GPIO_A0_NR,
-                       .label  = "GPA0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPA1(0),
-                       .ngpio  = EXYNOS4_GPIO_A1_NR,
-                       .label  = "GPA1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPB(0),
-                       .ngpio  = EXYNOS4_GPIO_B_NR,
-                       .label  = "GPB",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPC0(0),
-                       .ngpio  = EXYNOS4_GPIO_C0_NR,
-                       .label  = "GPC0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPC1(0),
-                       .ngpio  = EXYNOS4_GPIO_C1_NR,
-                       .label  = "GPC1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPD0(0),
-                       .ngpio  = EXYNOS4_GPIO_D0_NR,
-                       .label  = "GPD0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPD1(0),
-                       .ngpio  = EXYNOS4_GPIO_D1_NR,
-                       .label  = "GPD1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPE0(0),
-                       .ngpio  = EXYNOS4_GPIO_E0_NR,
-                       .label  = "GPE0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPE1(0),
-                       .ngpio  = EXYNOS4_GPIO_E1_NR,
-                       .label  = "GPE1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPE2(0),
-                       .ngpio  = EXYNOS4_GPIO_E2_NR,
-                       .label  = "GPE2",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPE3(0),
-                       .ngpio  = EXYNOS4_GPIO_E3_NR,
-                       .label  = "GPE3",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPE4(0),
-                       .ngpio  = EXYNOS4_GPIO_E4_NR,
-                       .label  = "GPE4",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPF0(0),
-                       .ngpio  = EXYNOS4_GPIO_F0_NR,
-                       .label  = "GPF0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPF1(0),
-                       .ngpio  = EXYNOS4_GPIO_F1_NR,
-                       .label  = "GPF1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPF2(0),
-                       .ngpio  = EXYNOS4_GPIO_F2_NR,
-                       .label  = "GPF2",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPF3(0),
-                       .ngpio  = EXYNOS4_GPIO_F3_NR,
-                       .label  = "GPF3",
-               },
-       },
-};
-#endif
-
-#ifdef CONFIG_ARCH_EXYNOS4
-static struct samsung_gpio_chip exynos4_gpios_2[] = {
-       {
-               .chip   = {
-                       .base   = EXYNOS4_GPJ0(0),
-                       .ngpio  = EXYNOS4_GPIO_J0_NR,
-                       .label  = "GPJ0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPJ1(0),
-                       .ngpio  = EXYNOS4_GPIO_J1_NR,
-                       .label  = "GPJ1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPK0(0),
-                       .ngpio  = EXYNOS4_GPIO_K0_NR,
-                       .label  = "GPK0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPK1(0),
-                       .ngpio  = EXYNOS4_GPIO_K1_NR,
-                       .label  = "GPK1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPK2(0),
-                       .ngpio  = EXYNOS4_GPIO_K2_NR,
-                       .label  = "GPK2",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPK3(0),
-                       .ngpio  = EXYNOS4_GPIO_K3_NR,
-                       .label  = "GPK3",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPL0(0),
-                       .ngpio  = EXYNOS4_GPIO_L0_NR,
-                       .label  = "GPL0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPL1(0),
-                       .ngpio  = EXYNOS4_GPIO_L1_NR,
-                       .label  = "GPL1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS4_GPL2(0),
-                       .ngpio  = EXYNOS4_GPIO_L2_NR,
-                       .label  = "GPL2",
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[8],
-               .chip   = {
-                       .base   = EXYNOS4_GPY0(0),
-                       .ngpio  = EXYNOS4_GPIO_Y0_NR,
-                       .label  = "GPY0",
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[8],
-               .chip   = {
-                       .base   = EXYNOS4_GPY1(0),
-                       .ngpio  = EXYNOS4_GPIO_Y1_NR,
-                       .label  = "GPY1",
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[8],
-               .chip   = {
-                       .base   = EXYNOS4_GPY2(0),
-                       .ngpio  = EXYNOS4_GPIO_Y2_NR,
-                       .label  = "GPY2",
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[8],
-               .chip   = {
-                       .base   = EXYNOS4_GPY3(0),
-                       .ngpio  = EXYNOS4_GPIO_Y3_NR,
-                       .label  = "GPY3",
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[8],
-               .chip   = {
-                       .base   = EXYNOS4_GPY4(0),
-                       .ngpio  = EXYNOS4_GPIO_Y4_NR,
-                       .label  = "GPY4",
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[8],
-               .chip   = {
-                       .base   = EXYNOS4_GPY5(0),
-                       .ngpio  = EXYNOS4_GPIO_Y5_NR,
-                       .label  = "GPY5",
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[8],
-               .chip   = {
-                       .base   = EXYNOS4_GPY6(0),
-                       .ngpio  = EXYNOS4_GPIO_Y6_NR,
-                       .label  = "GPY6",
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[9],
-               .irq_base = IRQ_EINT(0),
-               .chip   = {
-                       .base   = EXYNOS4_GPX0(0),
-                       .ngpio  = EXYNOS4_GPIO_X0_NR,
-                       .label  = "GPX0",
-                       .to_irq = samsung_gpiolib_to_irq,
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[9],
-               .irq_base = IRQ_EINT(8),
-               .chip   = {
-                       .base   = EXYNOS4_GPX1(0),
-                       .ngpio  = EXYNOS4_GPIO_X1_NR,
-                       .label  = "GPX1",
-                       .to_irq = samsung_gpiolib_to_irq,
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[9],
-               .irq_base = IRQ_EINT(16),
-               .chip   = {
-                       .base   = EXYNOS4_GPX2(0),
-                       .ngpio  = EXYNOS4_GPIO_X2_NR,
-                       .label  = "GPX2",
-                       .to_irq = samsung_gpiolib_to_irq,
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[9],
-               .irq_base = IRQ_EINT(24),
-               .chip   = {
-                       .base   = EXYNOS4_GPX3(0),
-                       .ngpio  = EXYNOS4_GPIO_X3_NR,
-                       .label  = "GPX3",
-                       .to_irq = samsung_gpiolib_to_irq,
-               },
-       },
-};
-#endif
-
-#ifdef CONFIG_ARCH_EXYNOS4
-static struct samsung_gpio_chip exynos4_gpios_3[] = {
-       {
-               .chip   = {
-                       .base   = EXYNOS4_GPZ(0),
-                       .ngpio  = EXYNOS4_GPIO_Z_NR,
-                       .label  = "GPZ",
-               },
-       },
-};
-#endif
-
-#ifdef CONFIG_SOC_EXYNOS5250
-static struct samsung_gpio_chip exynos5_gpios_1[] = {
-       {
-               .chip   = {
-                       .base   = EXYNOS5_GPA0(0),
-                       .ngpio  = EXYNOS5_GPIO_A0_NR,
-                       .label  = "GPA0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPA1(0),
-                       .ngpio  = EXYNOS5_GPIO_A1_NR,
-                       .label  = "GPA1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPA2(0),
-                       .ngpio  = EXYNOS5_GPIO_A2_NR,
-                       .label  = "GPA2",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPB0(0),
-                       .ngpio  = EXYNOS5_GPIO_B0_NR,
-                       .label  = "GPB0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPB1(0),
-                       .ngpio  = EXYNOS5_GPIO_B1_NR,
-                       .label  = "GPB1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPB2(0),
-                       .ngpio  = EXYNOS5_GPIO_B2_NR,
-                       .label  = "GPB2",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPB3(0),
-                       .ngpio  = EXYNOS5_GPIO_B3_NR,
-                       .label  = "GPB3",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPC0(0),
-                       .ngpio  = EXYNOS5_GPIO_C0_NR,
-                       .label  = "GPC0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPC1(0),
-                       .ngpio  = EXYNOS5_GPIO_C1_NR,
-                       .label  = "GPC1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPC2(0),
-                       .ngpio  = EXYNOS5_GPIO_C2_NR,
-                       .label  = "GPC2",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPC3(0),
-                       .ngpio  = EXYNOS5_GPIO_C3_NR,
-                       .label  = "GPC3",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPD0(0),
-                       .ngpio  = EXYNOS5_GPIO_D0_NR,
-                       .label  = "GPD0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPD1(0),
-                       .ngpio  = EXYNOS5_GPIO_D1_NR,
-                       .label  = "GPD1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPY0(0),
-                       .ngpio  = EXYNOS5_GPIO_Y0_NR,
-                       .label  = "GPY0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPY1(0),
-                       .ngpio  = EXYNOS5_GPIO_Y1_NR,
-                       .label  = "GPY1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPY2(0),
-                       .ngpio  = EXYNOS5_GPIO_Y2_NR,
-                       .label  = "GPY2",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPY3(0),
-                       .ngpio  = EXYNOS5_GPIO_Y3_NR,
-                       .label  = "GPY3",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPY4(0),
-                       .ngpio  = EXYNOS5_GPIO_Y4_NR,
-                       .label  = "GPY4",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPY5(0),
-                       .ngpio  = EXYNOS5_GPIO_Y5_NR,
-                       .label  = "GPY5",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPY6(0),
-                       .ngpio  = EXYNOS5_GPIO_Y6_NR,
-                       .label  = "GPY6",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPC4(0),
-                       .ngpio  = EXYNOS5_GPIO_C4_NR,
-                       .label  = "GPC4",
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[9],
-               .irq_base = IRQ_EINT(0),
-               .chip   = {
-                       .base   = EXYNOS5_GPX0(0),
-                       .ngpio  = EXYNOS5_GPIO_X0_NR,
-                       .label  = "GPX0",
-                       .to_irq = samsung_gpiolib_to_irq,
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[9],
-               .irq_base = IRQ_EINT(8),
-               .chip   = {
-                       .base   = EXYNOS5_GPX1(0),
-                       .ngpio  = EXYNOS5_GPIO_X1_NR,
-                       .label  = "GPX1",
-                       .to_irq = samsung_gpiolib_to_irq,
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[9],
-               .irq_base = IRQ_EINT(16),
-               .chip   = {
-                       .base   = EXYNOS5_GPX2(0),
-                       .ngpio  = EXYNOS5_GPIO_X2_NR,
-                       .label  = "GPX2",
-                       .to_irq = samsung_gpiolib_to_irq,
-               },
-       }, {
-               .config = &samsung_gpio_cfgs[9],
-               .irq_base = IRQ_EINT(24),
-               .chip   = {
-                       .base   = EXYNOS5_GPX3(0),
-                       .ngpio  = EXYNOS5_GPIO_X3_NR,
-                       .label  = "GPX3",
-                       .to_irq = samsung_gpiolib_to_irq,
-               },
-       },
-};
-#endif
-
-#ifdef CONFIG_SOC_EXYNOS5250
-static struct samsung_gpio_chip exynos5_gpios_2[] = {
-       {
-               .chip   = {
-                       .base   = EXYNOS5_GPE0(0),
-                       .ngpio  = EXYNOS5_GPIO_E0_NR,
-                       .label  = "GPE0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPE1(0),
-                       .ngpio  = EXYNOS5_GPIO_E1_NR,
-                       .label  = "GPE1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPF0(0),
-                       .ngpio  = EXYNOS5_GPIO_F0_NR,
-                       .label  = "GPF0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPF1(0),
-                       .ngpio  = EXYNOS5_GPIO_F1_NR,
-                       .label  = "GPF1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPG0(0),
-                       .ngpio  = EXYNOS5_GPIO_G0_NR,
-                       .label  = "GPG0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPG1(0),
-                       .ngpio  = EXYNOS5_GPIO_G1_NR,
-                       .label  = "GPG1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPG2(0),
-                       .ngpio  = EXYNOS5_GPIO_G2_NR,
-                       .label  = "GPG2",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPH0(0),
-                       .ngpio  = EXYNOS5_GPIO_H0_NR,
-                       .label  = "GPH0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPH1(0),
-                       .ngpio  = EXYNOS5_GPIO_H1_NR,
-                       .label  = "GPH1",
-
-               },
-       },
-};
-#endif
-
-#ifdef CONFIG_SOC_EXYNOS5250
-static struct samsung_gpio_chip exynos5_gpios_3[] = {
-       {
-               .chip   = {
-                       .base   = EXYNOS5_GPV0(0),
-                       .ngpio  = EXYNOS5_GPIO_V0_NR,
-                       .label  = "GPV0",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPV1(0),
-                       .ngpio  = EXYNOS5_GPIO_V1_NR,
-                       .label  = "GPV1",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPV2(0),
-                       .ngpio  = EXYNOS5_GPIO_V2_NR,
-                       .label  = "GPV2",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPV3(0),
-                       .ngpio  = EXYNOS5_GPIO_V3_NR,
-                       .label  = "GPV3",
-               },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPV4(0),
-                       .ngpio  = EXYNOS5_GPIO_V4_NR,
-                       .label  = "GPV4",
-               },
-       },
-};
-#endif
-
-#ifdef CONFIG_SOC_EXYNOS5250
-static struct samsung_gpio_chip exynos5_gpios_4[] = {
-       {
-               .chip   = {
-                       .base   = EXYNOS5_GPZ(0),
-                       .ngpio  = EXYNOS5_GPIO_Z_NR,
-                       .label  = "GPZ",
-               },
-       },
-};
-#endif
-
-
-#if defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF)
-static int exynos_gpio_xlate(struct gpio_chip *gc,
-                       const struct of_phandle_args *gpiospec, u32 *flags)
-{
-       unsigned int pin;
-
-       if (WARN_ON(gc->of_gpio_n_cells < 4))
-               return -EINVAL;
-
-       if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
-               return -EINVAL;
-
-       if (gpiospec->args[0] > gc->ngpio)
-               return -EINVAL;
-
-       pin = gc->base + gpiospec->args[0];
-
-       if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1])))
-               pr_warn("gpio_xlate: failed to set pin function\n");
-       if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff))
-               pr_warn("gpio_xlate: failed to set pin pull up/down\n");
-       if (s5p_gpio_set_drvstr(pin, gpiospec->args[3]))
-               pr_warn("gpio_xlate: failed to set pin drive strength\n");
-
-       if (flags)
-               *flags = gpiospec->args[2] >> 16;
-
-       return gpiospec->args[0];
-}
-
-static const struct of_device_id exynos_gpio_dt_match[] __initdata = {
-       { .compatible = "samsung,exynos4-gpio", },
-       {}
-};
-
-static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
-                                               u64 base, u64 offset)
-{
-       struct gpio_chip *gc =  &chip->chip;
-       u64 address;
-
-       if (!of_have_populated_dt())
-               return;
-
-       address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset;
-       gc->of_node = of_find_matching_node_by_address(NULL,
-                       exynos_gpio_dt_match, address);
-       if (!gc->of_node) {
-               pr_info("gpio: device tree node not found for gpio controller"
-                       " with base address %08llx\n", address);
-               return;
-       }
-       gc->of_gpio_n_cells = 4;
-       gc->of_xlate = exynos_gpio_xlate;
-}
-#elif defined(CONFIG_ARCH_EXYNOS)
-static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
-                                               u64 base, u64 offset)
-{
-       return;
-}
-#endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */
-
-static __init void exynos4_gpiolib_init(void)
-{
-#ifdef CONFIG_CPU_EXYNOS4210
-       struct samsung_gpio_chip *chip;
-       int i, nr_chips;
-       void __iomem *gpio_base1, *gpio_base2, *gpio_base3;
-       int group = 0;
-       void __iomem *gpx_base;
-
-       /* gpio part1 */
-       gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K);
-       if (gpio_base1 == NULL) {
-               pr_err("unable to ioremap for gpio_base1\n");
-               goto err_ioremap1;
-       }
-
-       chip = exynos4_gpios_1;
-       nr_chips = ARRAY_SIZE(exynos4_gpios_1);
-
-       for (i = 0; i < nr_chips; i++, chip++) {
-               if (!chip->config) {
-                       chip->config = &exynos_gpio_cfg;
-                       chip->group = group++;
-               }
-               exynos_gpiolib_attach_ofnode(chip,
-                               EXYNOS4_PA_GPIO1, i * 0x20);
-       }
-       samsung_gpiolib_add_4bit_chips(exynos4_gpios_1,
-                                      nr_chips, gpio_base1);
-
-       /* gpio part2 */
-       gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
-       if (gpio_base2 == NULL) {
-               pr_err("unable to ioremap for gpio_base2\n");
-               goto err_ioremap2;
-       }
-
-       /* need to set base address for gpx */
-       chip = &exynos4_gpios_2[16];
-       gpx_base = gpio_base2 + 0xC00;
-       for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
-               chip->base = gpx_base;
-
-       chip = exynos4_gpios_2;
-       nr_chips = ARRAY_SIZE(exynos4_gpios_2);
-
-       for (i = 0; i < nr_chips; i++, chip++) {
-               if (!chip->config) {
-                       chip->config = &exynos_gpio_cfg;
-                       chip->group = group++;
-               }
-               exynos_gpiolib_attach_ofnode(chip,
-                               EXYNOS4_PA_GPIO2, i * 0x20);
-       }
-       samsung_gpiolib_add_4bit_chips(exynos4_gpios_2,
-                                      nr_chips, gpio_base2);
-
-       /* gpio part3 */
-       gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256);
-       if (gpio_base3 == NULL) {
-               pr_err("unable to ioremap for gpio_base3\n");
-               goto err_ioremap3;
-       }
-
-       chip = exynos4_gpios_3;
-       nr_chips = ARRAY_SIZE(exynos4_gpios_3);
-
-       for (i = 0; i < nr_chips; i++, chip++) {
-               if (!chip->config) {
-                       chip->config = &exynos_gpio_cfg;
-                       chip->group = group++;
-               }
-               exynos_gpiolib_attach_ofnode(chip,
-                               EXYNOS4_PA_GPIO3, i * 0x20);
-       }
-       samsung_gpiolib_add_4bit_chips(exynos4_gpios_3,
-                                      nr_chips, gpio_base3);
-
-#if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT)
-       s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
-       s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
-#endif
-
-       return;
-
-err_ioremap3:
-       iounmap(gpio_base2);
-err_ioremap2:
-       iounmap(gpio_base1);
-err_ioremap1:
-       return;
-#endif /* CONFIG_CPU_EXYNOS4210 */
-}
-
-static __init void exynos5_gpiolib_init(void)
-{
-#ifdef CONFIG_SOC_EXYNOS5250
-       struct samsung_gpio_chip *chip;
-       int i, nr_chips;
-       void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4;
-       int group = 0;
-       void __iomem *gpx_base;
-
-       /* gpio part1 */
-       gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
-       if (gpio_base1 == NULL) {
-               pr_err("unable to ioremap for gpio_base1\n");
-               goto err_ioremap1;
-       }
-
-       /* need to set base address for gpc4 */
-       exynos5_gpios_1[20].base = gpio_base1 + 0x2E0;
-
-       /* need to set base address for gpx */
-       chip = &exynos5_gpios_1[21];
-       gpx_base = gpio_base1 + 0xC00;
-       for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
-               chip->base = gpx_base;
-
-       chip = exynos5_gpios_1;
-       nr_chips = ARRAY_SIZE(exynos5_gpios_1);
-
-       for (i = 0; i < nr_chips; i++, chip++) {
-               if (!chip->config) {
-                       chip->config = &exynos_gpio_cfg;
-                       chip->group = group++;
-               }
-               exynos_gpiolib_attach_ofnode(chip,
-                               EXYNOS5_PA_GPIO1, i * 0x20);
-       }
-       samsung_gpiolib_add_4bit_chips(exynos5_gpios_1,
-                                      nr_chips, gpio_base1);
-
-       /* gpio part2 */
-       gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K);
-       if (gpio_base2 == NULL) {
-               pr_err("unable to ioremap for gpio_base2\n");
-               goto err_ioremap2;
-       }
-
-       chip = exynos5_gpios_2;
-       nr_chips = ARRAY_SIZE(exynos5_gpios_2);
-
-       for (i = 0; i < nr_chips; i++, chip++) {
-               if (!chip->config) {
-                       chip->config = &exynos_gpio_cfg;
-                       chip->group = group++;
-               }
-               exynos_gpiolib_attach_ofnode(chip,
-                               EXYNOS5_PA_GPIO2, i * 0x20);
-       }
-       samsung_gpiolib_add_4bit_chips(exynos5_gpios_2,
-                                      nr_chips, gpio_base2);
-
-       /* gpio part3 */
-       gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K);
-       if (gpio_base3 == NULL) {
-               pr_err("unable to ioremap for gpio_base3\n");
-               goto err_ioremap3;
-       }
-
-       /* need to set base address for gpv */
-       exynos5_gpios_3[0].base = gpio_base3;
-       exynos5_gpios_3[1].base = gpio_base3 + 0x20;
-       exynos5_gpios_3[2].base = gpio_base3 + 0x60;
-       exynos5_gpios_3[3].base = gpio_base3 + 0x80;
-       exynos5_gpios_3[4].base = gpio_base3 + 0xC0;
-
-       chip = exynos5_gpios_3;
-       nr_chips = ARRAY_SIZE(exynos5_gpios_3);
-
-       for (i = 0; i < nr_chips; i++, chip++) {
-               if (!chip->config) {
-                       chip->config = &exynos_gpio_cfg;
-                       chip->group = group++;
-               }
-               exynos_gpiolib_attach_ofnode(chip,
-                               EXYNOS5_PA_GPIO3, i * 0x20);
-       }
-       samsung_gpiolib_add_4bit_chips(exynos5_gpios_3,
-                                      nr_chips, gpio_base3);
-
-       /* gpio part4 */
-       gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K);
-       if (gpio_base4 == NULL) {
-               pr_err("unable to ioremap for gpio_base4\n");
-               goto err_ioremap4;
-       }
-
-       chip = exynos5_gpios_4;
-       nr_chips = ARRAY_SIZE(exynos5_gpios_4);
-
-       for (i = 0; i < nr_chips; i++, chip++) {
-               if (!chip->config) {
-                       chip->config = &exynos_gpio_cfg;
-                       chip->group = group++;
-               }
-               exynos_gpiolib_attach_ofnode(chip,
-                               EXYNOS5_PA_GPIO4, i * 0x20);
-       }
-       samsung_gpiolib_add_4bit_chips(exynos5_gpios_4,
-                                      nr_chips, gpio_base4);
-       return;
-
-err_ioremap4:
-       iounmap(gpio_base3);
-err_ioremap3:
-       iounmap(gpio_base2);
-err_ioremap2:
-       iounmap(gpio_base1);
-err_ioremap1:
-       return;
-
-#endif /* CONFIG_SOC_EXYNOS5250 */
-}
-
 /* TODO: cleanup soc_is_* */
 static __init int samsung_gpiolib_init(void)
 {
@@ -3040,10 +2173,6 @@ static __init int samsung_gpiolib_init(void)
 #if defined(CONFIG_CPU_S5PV210) && defined(CONFIG_S5P_GPIO_INT)
                s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
 #endif
-       } else if (soc_is_exynos4210()) {
-               exynos4_gpiolib_init();
-       } else if (soc_is_exynos5250()) {
-               exynos5_gpiolib_init();
        } else {
                WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n");
                return -ENODEV;
index 7a4bf7c0d98f266197f3d06fa069564f2028cbeb..e9a0415834ea5240e16994420660ea5131744070 100644 (file)
@@ -128,18 +128,13 @@ static int spics_gpio_probe(struct platform_device *pdev)
        struct resource *res;
        int ret;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n");
-               return -EBUSY;
-       }
-
        spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL);
        if (!spics) {
                dev_err(&pdev->dev, "memory allocation fail\n");
                return -ENOMEM;
        }
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        spics->base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(spics->base))
                return PTR_ERR(spics->base);
index f43ab6aea281d2f20c03608a495a32b4c0ed2d49..f2fb12c18da97616b24b9232ac7ce8d271424115 100644 (file)
@@ -361,7 +361,7 @@ static int gsta_probe(struct platform_device *dev)
        struct gsta_gpio *chip;
        struct resource *res;
 
-       pdev = *(struct pci_dev **)(dev->dev.platform_data);
+       pdev = *(struct pci_dev **)dev_get_platdata(&dev->dev);
        gpio_pdata = dev_get_platdata(&pdev->dev);
 
        if (gpio_pdata == NULL)
index f371732591d2ab894798dd224dab6062094bfec0..d2983e9ad6af78ee1705b6377cea93f5de41d245 100644 (file)
@@ -583,7 +583,7 @@ static int sx150x_probe(struct i2c_client *client,
        struct sx150x_chip *chip;
        int rc;
 
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
        if (!pdata)
                return -EINVAL;
 
index 4c65f8883204b95417c143e61aa5e3d9027ea5c9..7a0e956ef1ed1b47d8d034bf8e48ed3f812010f3 100644 (file)
@@ -227,7 +227,7 @@ static int timbgpio_probe(struct platform_device *pdev)
        struct gpio_chip *gc;
        struct timbgpio *tgpio;
        struct resource *iomem;
-       struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
+       struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int irq = platform_get_irq(pdev, 0);
 
        if (!pdata || pdata->nr_pins > 32) {
@@ -318,7 +318,7 @@ err_mem:
 static int timbgpio_remove(struct platform_device *pdev)
 {
        int err;
-       struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
+       struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct timbgpio *tgpio = platform_get_drvdata(pdev);
        struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        int irq = platform_get_irq(pdev, 0);
index 30a5844a7dca212d0d36f17c6ccc26b6778e59b8..276a4229b032583379dd1490716dd98565c6bca3 100644 (file)
@@ -87,7 +87,7 @@ static struct gpio_chip template_chip = {
 static int tps65912_gpio_probe(struct platform_device *pdev)
 {
        struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent);
-       struct tps65912_board *pdata = tps65912->dev->platform_data;
+       struct tps65912_board *pdata = dev_get_platdata(tps65912->dev);
        struct tps65912_gpio_data *tps65912_gpio;
        int ret;
 
index cc53cab8df2acb89042673347acf128056c57026..3df3ebdb3e5267f5e4ea1575ff9d6217a950f36a 100644 (file)
@@ -322,7 +322,7 @@ static void ts5500_disable_irq(struct ts5500_priv *priv)
 static int ts5500_dio_probe(struct platform_device *pdev)
 {
        enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data;
-       struct ts5500_dio_platform_data *pdata = pdev->dev.platform_data;
+       struct ts5500_dio_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct device *dev = &pdev->dev;
        const char *name = dev_name(dev);
        struct ts5500_priv *priv;
index 4d330e36da1da0e6c68a3dcd40a075c571f857bd..d8e4f6efcb29315fe77f6cecc52d3048c3e1f270 100644 (file)
@@ -256,7 +256,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
                /* optionally have the first two GPIOs switch vMMC1
                 * and vMMC2 power supplies based on card presence.
                 */
-               pdata = chip->dev->platform_data;
+               pdata = dev_get_platdata(chip->dev);
                if (pdata)
                        value |= pdata->mmc_cd & 0x03;
 
@@ -460,7 +460,7 @@ static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev)
 
 static int gpio_twl4030_probe(struct platform_device *pdev)
 {
-       struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
+       struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct device_node *node = pdev->dev.of_node;
        struct gpio_twl4030_priv *priv;
        int ret, irq_base;
@@ -556,7 +556,7 @@ out:
 /* Cannot use as gpio_twl4030_probe() calls us */
 static int gpio_twl4030_remove(struct platform_device *pdev)
 {
-       struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
+       struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev);
        int status;
 
index 0be82c6dd796cf5e0daac94f1804afcef8750273..d420d30b86e73233314b74f36d8412b4e0c01166 100644 (file)
@@ -84,15 +84,11 @@ static struct gpio_chip twl6040gpo_chip = {
 
 static int gpo_twl6040_probe(struct platform_device *pdev)
 {
-       struct twl6040_gpo_data *pdata = pdev->dev.platform_data;
        struct device *twl6040_core_dev = pdev->dev.parent;
        struct twl6040 *twl6040 = dev_get_drvdata(twl6040_core_dev);
        int ret;
 
-       if (pdata)
-               twl6040gpo_chip.base = pdata->gpio_base;
-       else
-               twl6040gpo_chip.base = -1;
+       twl6040gpo_chip.base = -1;
 
        if (twl6040_get_revid(twl6040) < TWL6041_REV_ES2_0)
                twl6040gpo_chip.ngpio = 3; /* twl6040 have 3 GPO */
diff --git a/drivers/gpio/gpio-tz1090-pdc.c b/drivers/gpio/gpio-tz1090-pdc.c
new file mode 100644 (file)
index 0000000..f512da2
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Toumaz Xenif TZ1090 PDC GPIO handling.
+ *
+ * Copyright (C) 2012-2013 Imagination Technologies Ltd.
+ *
+ * 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/bitops.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/syscore_ops.h>
+#include <asm/global_lock.h>
+
+/* Register offsets from SOC_GPIO_CONTROL0 */
+#define REG_SOC_GPIO_CONTROL0  0x00
+#define REG_SOC_GPIO_CONTROL1  0x04
+#define REG_SOC_GPIO_CONTROL2  0x08
+#define REG_SOC_GPIO_CONTROL3  0x0c
+#define REG_SOC_GPIO_STATUS    0x80
+
+/* PDC GPIOs go after normal GPIOs */
+#define GPIO_PDC_BASE          90
+#define GPIO_PDC_NGPIO         7
+
+/* Out of PDC gpios, only syswakes have irqs */
+#define GPIO_PDC_IRQ_FIRST     2
+#define GPIO_PDC_NIRQ          3
+
+/**
+ * struct tz1090_pdc_gpio - GPIO bank private data
+ * @chip:      Generic GPIO chip for GPIO bank
+ * @reg:       Base of registers, offset for this GPIO bank
+ * @irq:       IRQ numbers for Syswake GPIOs
+ *
+ * This is the main private data for the PDC GPIO driver. It encapsulates a
+ * gpio_chip, and the callbacks for the gpio_chip can access the private data
+ * with the to_pdc() macro below.
+ */
+struct tz1090_pdc_gpio {
+       struct gpio_chip chip;
+       void __iomem *reg;
+       int irq[GPIO_PDC_NIRQ];
+};
+#define to_pdc(c)      container_of(c, struct tz1090_pdc_gpio, chip)
+
+/* Register accesses into the PDC MMIO area */
+
+static inline void pdc_write(struct tz1090_pdc_gpio *priv, unsigned int reg_offs,
+                     unsigned int data)
+{
+       writel(data, priv->reg + reg_offs);
+}
+
+static inline unsigned int pdc_read(struct tz1090_pdc_gpio *priv,
+                            unsigned int reg_offs)
+{
+       return readl(priv->reg + reg_offs);
+}
+
+/* Generic GPIO interface */
+
+static int tz1090_pdc_gpio_direction_input(struct gpio_chip *chip,
+                                          unsigned int offset)
+{
+       struct tz1090_pdc_gpio *priv = to_pdc(chip);
+       u32 value;
+       int lstat;
+
+       __global_lock2(lstat);
+       value = pdc_read(priv, REG_SOC_GPIO_CONTROL1);
+       value |= BIT(offset);
+       pdc_write(priv, REG_SOC_GPIO_CONTROL1, value);
+       __global_unlock2(lstat);
+
+       return 0;
+}
+
+static int tz1090_pdc_gpio_direction_output(struct gpio_chip *chip,
+                                           unsigned int offset,
+                                           int output_value)
+{
+       struct tz1090_pdc_gpio *priv = to_pdc(chip);
+       u32 value;
+       int lstat;
+
+       __global_lock2(lstat);
+       /* EXT_POWER doesn't seem to have an output value bit */
+       if (offset < 6) {
+               value = pdc_read(priv, REG_SOC_GPIO_CONTROL0);
+               if (output_value)
+                       value |= BIT(offset);
+               else
+                       value &= ~BIT(offset);
+               pdc_write(priv, REG_SOC_GPIO_CONTROL0, value);
+       }
+
+       value = pdc_read(priv, REG_SOC_GPIO_CONTROL1);
+       value &= ~BIT(offset);
+       pdc_write(priv, REG_SOC_GPIO_CONTROL1, value);
+       __global_unlock2(lstat);
+
+       return 0;
+}
+
+static int tz1090_pdc_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct tz1090_pdc_gpio *priv = to_pdc(chip);
+       return pdc_read(priv, REG_SOC_GPIO_STATUS) & BIT(offset);
+}
+
+static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset,
+                               int output_value)
+{
+       struct tz1090_pdc_gpio *priv = to_pdc(chip);
+       u32 value;
+       int lstat;
+
+       /* EXT_POWER doesn't seem to have an output value bit */
+       if (offset >= 6)
+               return;
+
+       __global_lock2(lstat);
+       value = pdc_read(priv, REG_SOC_GPIO_CONTROL0);
+       if (output_value)
+               value |= BIT(offset);
+       else
+               value &= ~BIT(offset);
+       pdc_write(priv, REG_SOC_GPIO_CONTROL0, value);
+       __global_unlock2(lstat);
+}
+
+static int tz1090_pdc_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+       return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void tz1090_pdc_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+       pinctrl_free_gpio(chip->base + offset);
+}
+
+static int tz1090_pdc_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+       struct tz1090_pdc_gpio *priv = to_pdc(chip);
+       unsigned int syswake = offset - GPIO_PDC_IRQ_FIRST;
+       int irq;
+
+       /* only syswakes have irqs */
+       if (syswake >= GPIO_PDC_NIRQ)
+               return -EINVAL;
+
+       irq = priv->irq[syswake];
+       if (!irq)
+               return -EINVAL;
+
+       return irq;
+}
+
+static int tz1090_pdc_gpio_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct resource *res_regs;
+       struct tz1090_pdc_gpio *priv;
+       unsigned int i;
+
+       if (!np) {
+               dev_err(&pdev->dev, "must be instantiated via devicetree\n");
+               return -ENOENT;
+       }
+
+       res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res_regs) {
+               dev_err(&pdev->dev, "cannot find registers resource\n");
+               return -ENOENT;
+       }
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(&pdev->dev, "unable to allocate driver data\n");
+               return -ENOMEM;
+       }
+
+       /* Ioremap the registers */
+       priv->reg = devm_ioremap(&pdev->dev, res_regs->start,
+                                res_regs->end - res_regs->start);
+       if (!priv->reg) {
+               dev_err(&pdev->dev, "unable to ioremap registers\n");
+               return -ENOMEM;
+       }
+
+       /* Set up GPIO chip */
+       priv->chip.label                = "tz1090-pdc-gpio";
+       priv->chip.dev                  = &pdev->dev;
+       priv->chip.direction_input      = tz1090_pdc_gpio_direction_input;
+       priv->chip.direction_output     = tz1090_pdc_gpio_direction_output;
+       priv->chip.get                  = tz1090_pdc_gpio_get;
+       priv->chip.set                  = tz1090_pdc_gpio_set;
+       priv->chip.free                 = tz1090_pdc_gpio_free;
+       priv->chip.request              = tz1090_pdc_gpio_request;
+       priv->chip.to_irq               = tz1090_pdc_gpio_to_irq;
+       priv->chip.of_node              = np;
+
+       /* GPIO numbering */
+       priv->chip.base                 = GPIO_PDC_BASE;
+       priv->chip.ngpio                = GPIO_PDC_NGPIO;
+
+       /* Map the syswake irqs */
+       for (i = 0; i < GPIO_PDC_NIRQ; ++i)
+               priv->irq[i] = irq_of_parse_and_map(np, i);
+
+       /* Add the GPIO bank */
+       gpiochip_add(&priv->chip);
+
+       return 0;
+}
+
+static struct of_device_id tz1090_pdc_gpio_of_match[] = {
+       { .compatible = "img,tz1090-pdc-gpio" },
+       { },
+};
+
+static struct platform_driver tz1090_pdc_gpio_driver = {
+       .driver = {
+               .name           = "tz1090-pdc-gpio",
+               .owner          = THIS_MODULE,
+               .of_match_table = tz1090_pdc_gpio_of_match,
+       },
+       .probe          = tz1090_pdc_gpio_probe,
+};
+
+static int __init tz1090_pdc_gpio_init(void)
+{
+       return platform_driver_register(&tz1090_pdc_gpio_driver);
+}
+subsys_initcall(tz1090_pdc_gpio_init);
diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c
new file mode 100644 (file)
index 0000000..23e0613
--- /dev/null
@@ -0,0 +1,606 @@
+/*
+ * Toumaz Xenif TZ1090 GPIO handling.
+ *
+ * Copyright (C) 2008-2013 Imagination Technologies Ltd.
+ *
+ *  Based on ARM PXA code and others.
+ *
+ * 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/bitops.h>
+#include <linux/export.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/syscore_ops.h>
+#include <asm/global_lock.h>
+
+/* Register offsets from bank base address */
+#define REG_GPIO_DIR           0x00
+#define REG_GPIO_IRQ_PLRT      0x20
+#define REG_GPIO_IRQ_TYPE      0x30
+#define REG_GPIO_IRQ_EN                0x40
+#define REG_GPIO_IRQ_STS       0x50
+#define REG_GPIO_BIT_EN                0x60
+#define REG_GPIO_DIN           0x70
+#define REG_GPIO_DOUT          0x80
+
+/* REG_GPIO_IRQ_PLRT */
+#define REG_GPIO_IRQ_PLRT_LOW  0
+#define REG_GPIO_IRQ_PLRT_HIGH 1
+
+/* REG_GPIO_IRQ_TYPE */
+#define REG_GPIO_IRQ_TYPE_LEVEL        0
+#define REG_GPIO_IRQ_TYPE_EDGE 1
+
+/**
+ * struct tz1090_gpio_bank - GPIO bank private data
+ * @chip:      Generic GPIO chip for GPIO bank
+ * @domain:    IRQ domain for GPIO bank (may be NULL)
+ * @reg:       Base of registers, offset for this GPIO bank
+ * @irq:       IRQ number for GPIO bank
+ * @label:     Debug GPIO bank label, used for storage of chip->label
+ *
+ * This is the main private data for a GPIO bank. It encapsulates a gpio_chip,
+ * and the callbacks for the gpio_chip can access the private data with the
+ * to_bank() macro below.
+ */
+struct tz1090_gpio_bank {
+       struct gpio_chip chip;
+       struct irq_domain *domain;
+       void __iomem *reg;
+       int irq;
+       char label[16];
+};
+#define to_bank(c)     container_of(c, struct tz1090_gpio_bank, chip)
+
+/**
+ * struct tz1090_gpio - Overall GPIO device private data
+ * @dev:       Device (from platform device)
+ * @reg:       Base of GPIO registers
+ *
+ * Represents the overall GPIO device. This structure is actually only
+ * temporary, and used during init.
+ */
+struct tz1090_gpio {
+       struct device *dev;
+       void __iomem *reg;
+};
+
+/**
+ * struct tz1090_gpio_bank_info - Temporary registration info for GPIO bank
+ * @priv:      Overall GPIO device private data
+ * @node:      Device tree node specific to this GPIO bank
+ * @index:     Index of bank in range 0-2
+ */
+struct tz1090_gpio_bank_info {
+       struct tz1090_gpio *priv;
+       struct device_node *node;
+       unsigned int index;
+};
+
+/* Convenience register accessors */
+static inline void tz1090_gpio_write(struct tz1090_gpio_bank *bank,
+                             unsigned int reg_offs, u32 data)
+{
+       iowrite32(data, bank->reg + reg_offs);
+}
+
+static inline u32 tz1090_gpio_read(struct tz1090_gpio_bank *bank,
+                           unsigned int reg_offs)
+{
+       return ioread32(bank->reg + reg_offs);
+}
+
+/* caller must hold LOCK2 */
+static inline void _tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank,
+                                         unsigned int reg_offs,
+                                         unsigned int offset)
+{
+       u32 value;
+
+       value = tz1090_gpio_read(bank, reg_offs);
+       value &= ~BIT(offset);
+       tz1090_gpio_write(bank, reg_offs, value);
+}
+
+static void tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank,
+                                 unsigned int reg_offs,
+                                 unsigned int offset)
+{
+       int lstat;
+
+       __global_lock2(lstat);
+       _tz1090_gpio_clear_bit(bank, reg_offs, offset);
+       __global_unlock2(lstat);
+}
+
+/* caller must hold LOCK2 */
+static inline void _tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank,
+                                       unsigned int reg_offs,
+                                       unsigned int offset)
+{
+       u32 value;
+
+       value = tz1090_gpio_read(bank, reg_offs);
+       value |= BIT(offset);
+       tz1090_gpio_write(bank, reg_offs, value);
+}
+
+static void tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank,
+                               unsigned int reg_offs,
+                               unsigned int offset)
+{
+       int lstat;
+
+       __global_lock2(lstat);
+       _tz1090_gpio_set_bit(bank, reg_offs, offset);
+       __global_unlock2(lstat);
+}
+
+/* caller must hold LOCK2 */
+static inline void _tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank,
+                                       unsigned int reg_offs,
+                                       unsigned int offset,
+                                       bool val)
+{
+       u32 value;
+
+       value = tz1090_gpio_read(bank, reg_offs);
+       value &= ~BIT(offset);
+       if (val)
+               value |= BIT(offset);
+       tz1090_gpio_write(bank, reg_offs, value);
+}
+
+static void tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank,
+                               unsigned int reg_offs,
+                               unsigned int offset,
+                               bool val)
+{
+       int lstat;
+
+       __global_lock2(lstat);
+       _tz1090_gpio_mod_bit(bank, reg_offs, offset, val);
+       __global_unlock2(lstat);
+}
+
+static inline int tz1090_gpio_read_bit(struct tz1090_gpio_bank *bank,
+                                      unsigned int reg_offs,
+                                      unsigned int offset)
+{
+       return tz1090_gpio_read(bank, reg_offs) & BIT(offset);
+}
+
+/* GPIO chip callbacks */
+
+static int tz1090_gpio_direction_input(struct gpio_chip *chip,
+                                      unsigned int offset)
+{
+       struct tz1090_gpio_bank *bank = to_bank(chip);
+       tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset);
+
+       return 0;
+}
+
+static int tz1090_gpio_direction_output(struct gpio_chip *chip,
+                                       unsigned int offset, int output_value)
+{
+       struct tz1090_gpio_bank *bank = to_bank(chip);
+       int lstat;
+
+       __global_lock2(lstat);
+       _tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value);
+       _tz1090_gpio_clear_bit(bank, REG_GPIO_DIR, offset);
+       __global_unlock2(lstat);
+
+       return 0;
+}
+
+/*
+ * Return GPIO level
+ */
+static int tz1090_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct tz1090_gpio_bank *bank = to_bank(chip);
+
+       return tz1090_gpio_read_bit(bank, REG_GPIO_DIN, offset);
+}
+
+/*
+ * Set output GPIO level
+ */
+static void tz1090_gpio_set(struct gpio_chip *chip, unsigned int offset,
+                           int output_value)
+{
+       struct tz1090_gpio_bank *bank = to_bank(chip);
+
+       tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value);
+}
+
+static int tz1090_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+       struct tz1090_gpio_bank *bank = to_bank(chip);
+       int ret;
+
+       ret = pinctrl_request_gpio(chip->base + offset);
+       if (ret)
+               return ret;
+
+       tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset);
+       tz1090_gpio_set_bit(bank, REG_GPIO_BIT_EN, offset);
+
+       return 0;
+}
+
+static void tz1090_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+       struct tz1090_gpio_bank *bank = to_bank(chip);
+
+       pinctrl_free_gpio(chip->base + offset);
+
+       tz1090_gpio_clear_bit(bank, REG_GPIO_BIT_EN, offset);
+}
+
+static int tz1090_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+       struct tz1090_gpio_bank *bank = to_bank(chip);
+
+       if (!bank->domain)
+               return -EINVAL;
+
+       return irq_create_mapping(bank->domain, offset);
+}
+
+/* IRQ chip handlers */
+
+/* Get TZ1090 GPIO chip from irq data provided to generic IRQ callbacks */
+static inline struct tz1090_gpio_bank *irqd_to_gpio_bank(struct irq_data *data)
+{
+       return (struct tz1090_gpio_bank *)data->domain->host_data;
+}
+
+static void tz1090_gpio_irq_polarity(struct tz1090_gpio_bank *bank,
+                                    unsigned int offset, unsigned int polarity)
+{
+       tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_PLRT, offset, polarity);
+}
+
+static void tz1090_gpio_irq_type(struct tz1090_gpio_bank *bank,
+                                unsigned int offset, unsigned int type)
+{
+       tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_TYPE, offset, type);
+}
+
+/* set polarity to trigger on next edge, whether rising or falling */
+static void tz1090_gpio_irq_next_edge(struct tz1090_gpio_bank *bank,
+                                     unsigned int offset)
+{
+       unsigned int value_p, value_i;
+       int lstat;
+
+       /*
+        * Set the GPIO's interrupt polarity to the opposite of the current
+        * input value so that the next edge triggers an interrupt.
+        */
+       __global_lock2(lstat);
+       value_i = ~tz1090_gpio_read(bank, REG_GPIO_DIN);
+       value_p = tz1090_gpio_read(bank, REG_GPIO_IRQ_PLRT);
+       value_p &= ~BIT(offset);
+       value_p |= value_i & BIT(offset);
+       tz1090_gpio_write(bank, REG_GPIO_IRQ_PLRT, value_p);
+       __global_unlock2(lstat);
+}
+
+static unsigned int gpio_startup_irq(struct irq_data *data)
+{
+       /*
+        * This warning indicates that the type of the irq hasn't been set
+        * before enabling the irq. This would normally be done by passing some
+        * trigger flags to request_irq().
+        */
+       WARN(irqd_get_trigger_type(data) == IRQ_TYPE_NONE,
+               "irq type not set before enabling gpio irq %d", data->irq);
+
+       irq_gc_ack_clr_bit(data);
+       irq_gc_mask_set_bit(data);
+       return 0;
+}
+
+static int gpio_set_irq_type(struct irq_data *data, unsigned int flow_type)
+{
+       struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data);
+       unsigned int type;
+       unsigned int polarity;
+
+       switch (flow_type) {
+       case IRQ_TYPE_EDGE_BOTH:
+               type = REG_GPIO_IRQ_TYPE_EDGE;
+               polarity = REG_GPIO_IRQ_PLRT_LOW;
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               type = REG_GPIO_IRQ_TYPE_EDGE;
+               polarity = REG_GPIO_IRQ_PLRT_HIGH;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               type = REG_GPIO_IRQ_TYPE_EDGE;
+               polarity = REG_GPIO_IRQ_PLRT_LOW;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               type = REG_GPIO_IRQ_TYPE_LEVEL;
+               polarity = REG_GPIO_IRQ_PLRT_HIGH;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               type = REG_GPIO_IRQ_TYPE_LEVEL;
+               polarity = REG_GPIO_IRQ_PLRT_LOW;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       tz1090_gpio_irq_type(bank, data->hwirq, type);
+       irq_setup_alt_chip(data, flow_type);
+
+       if (flow_type == IRQ_TYPE_EDGE_BOTH)
+               tz1090_gpio_irq_next_edge(bank, data->hwirq);
+       else
+               tz1090_gpio_irq_polarity(bank, data->hwirq, polarity);
+
+       return 0;
+}
+
+#ifdef CONFIG_SUSPEND
+static int gpio_set_irq_wake(struct irq_data *data, unsigned int on)
+{
+       struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data);
+
+#ifdef CONFIG_PM_DEBUG
+       pr_info("irq_wake irq%d state:%d\n", data->irq, on);
+#endif
+
+       /* wake on gpio block interrupt */
+       return irq_set_irq_wake(bank->irq, on);
+}
+#else
+#define gpio_set_irq_wake NULL
+#endif
+
+static void tz1090_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       irq_hw_number_t hw;
+       unsigned int irq_stat, irq_no;
+       struct tz1090_gpio_bank *bank;
+       struct irq_desc *child_desc;
+
+       bank = (struct tz1090_gpio_bank *)irq_desc_get_handler_data(desc);
+       irq_stat = tz1090_gpio_read(bank, REG_GPIO_DIR) &
+                  tz1090_gpio_read(bank, REG_GPIO_IRQ_STS) &
+                  tz1090_gpio_read(bank, REG_GPIO_IRQ_EN) &
+                  0x3FFFFFFF; /* 30 bits only */
+
+       for (hw = 0; irq_stat; irq_stat >>= 1, ++hw) {
+               if (!(irq_stat & 1))
+                       continue;
+
+               irq_no = irq_linear_revmap(bank->domain, hw);
+               child_desc = irq_to_desc(irq_no);
+
+               /* Toggle edge for pin with both edges triggering enabled */
+               if (irqd_get_trigger_type(&child_desc->irq_data)
+                               == IRQ_TYPE_EDGE_BOTH)
+                       tz1090_gpio_irq_next_edge(bank, hw);
+
+               generic_handle_irq_desc(irq_no, child_desc);
+       }
+}
+
+static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info)
+{
+       struct device_node *np = info->node;
+       struct device *dev = info->priv->dev;
+       struct tz1090_gpio_bank *bank;
+       struct irq_chip_generic *gc;
+       int err;
+
+       bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
+       if (!bank) {
+               dev_err(dev, "unable to allocate driver data\n");
+               return -ENOMEM;
+       }
+
+       /* Offset the main registers to the first register in this bank */
+       bank->reg = info->priv->reg + info->index * 4;
+
+       /* Set up GPIO chip */
+       snprintf(bank->label, sizeof(bank->label), "tz1090-gpio-%u",
+                info->index);
+       bank->chip.label                = bank->label;
+       bank->chip.dev                  = dev;
+       bank->chip.direction_input      = tz1090_gpio_direction_input;
+       bank->chip.direction_output     = tz1090_gpio_direction_output;
+       bank->chip.get                  = tz1090_gpio_get;
+       bank->chip.set                  = tz1090_gpio_set;
+       bank->chip.free                 = tz1090_gpio_free;
+       bank->chip.request              = tz1090_gpio_request;
+       bank->chip.to_irq               = tz1090_gpio_to_irq;
+       bank->chip.of_node              = np;
+
+       /* GPIO numbering from 0 */
+       bank->chip.base                 = info->index * 30;
+       bank->chip.ngpio                = 30;
+
+       /* Add the GPIO bank */
+       gpiochip_add(&bank->chip);
+
+       /* Get the GPIO bank IRQ if provided */
+       bank->irq = irq_of_parse_and_map(np, 0);
+
+       /* The interrupt is optional (it may be used by another core on chip) */
+       if (bank->irq < 0) {
+               dev_info(dev, "IRQ not provided for bank %u, IRQs disabled\n",
+                        info->index);
+               return 0;
+       }
+
+       dev_info(dev, "Setting up IRQs for GPIO bank %u\n",
+                info->index);
+
+       /*
+        * Initialise all interrupts to disabled so we don't get
+        * spurious ones on a dirty boot and hit the BUG_ON in the
+        * handler.
+        */
+       tz1090_gpio_write(bank, REG_GPIO_IRQ_EN, 0);
+
+       /* Add a virtual IRQ for each GPIO */
+       bank->domain = irq_domain_add_linear(np,
+                                            bank->chip.ngpio,
+                                            &irq_generic_chip_ops,
+                                            bank);
+
+       /* Set up a generic irq chip with 2 chip types (level and edge) */
+       err = irq_alloc_domain_generic_chips(bank->domain, bank->chip.ngpio, 2,
+                                            bank->label, handle_bad_irq, 0, 0,
+                                            IRQ_GC_INIT_NESTED_LOCK);
+       if (err) {
+               dev_info(dev,
+                        "irq_alloc_domain_generic_chips failed for bank %u, IRQs disabled\n",
+                        info->index);
+               irq_domain_remove(bank->domain);
+               return 0;
+       }
+
+       gc = irq_get_domain_generic_chip(bank->domain, 0);
+       gc->reg_base    = bank->reg;
+
+       /* level chip type */
+       gc->chip_types[0].type                  = IRQ_TYPE_LEVEL_MASK;
+       gc->chip_types[0].handler               = handle_level_irq;
+       gc->chip_types[0].regs.ack              = REG_GPIO_IRQ_STS;
+       gc->chip_types[0].regs.mask             = REG_GPIO_IRQ_EN;
+       gc->chip_types[0].chip.irq_startup      = gpio_startup_irq,
+       gc->chip_types[0].chip.irq_ack          = irq_gc_ack_clr_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     = gpio_set_irq_type,
+       gc->chip_types[0].chip.irq_set_wake     = gpio_set_irq_wake,
+       gc->chip_types[0].chip.flags            = IRQCHIP_MASK_ON_SUSPEND,
+
+       /* edge chip type */
+       gc->chip_types[1].type                  = IRQ_TYPE_EDGE_BOTH;
+       gc->chip_types[1].handler               = handle_edge_irq;
+       gc->chip_types[1].regs.ack              = REG_GPIO_IRQ_STS;
+       gc->chip_types[1].regs.mask             = REG_GPIO_IRQ_EN;
+       gc->chip_types[1].chip.irq_startup      = gpio_startup_irq,
+       gc->chip_types[1].chip.irq_ack          = irq_gc_ack_clr_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     = gpio_set_irq_type,
+       gc->chip_types[1].chip.irq_set_wake     = gpio_set_irq_wake,
+       gc->chip_types[1].chip.flags            = IRQCHIP_MASK_ON_SUSPEND,
+
+       /* Setup chained handler for this GPIO bank */
+       irq_set_handler_data(bank->irq, bank);
+       irq_set_chained_handler(bank->irq, tz1090_gpio_irq_handler);
+
+       return 0;
+}
+
+static void tz1090_gpio_register_banks(struct tz1090_gpio *priv)
+{
+       struct device_node *np = priv->dev->of_node;
+       struct device_node *node;
+
+       for_each_available_child_of_node(np, node) {
+               struct tz1090_gpio_bank_info info;
+               u32 addr;
+               int ret;
+
+               ret = of_property_read_u32(node, "reg", &addr);
+               if (ret) {
+                       dev_err(priv->dev, "invalid reg on %s\n",
+                               node->full_name);
+                       continue;
+               }
+               if (addr >= 3) {
+                       dev_err(priv->dev, "index %u in %s out of range\n",
+                               addr, node->full_name);
+                       continue;
+               }
+
+               info.index = addr;
+               info.node = of_node_get(node);
+               info.priv = priv;
+
+               ret = tz1090_gpio_bank_probe(&info);
+               if (ret) {
+                       dev_err(priv->dev, "failure registering %s\n",
+                               node->full_name);
+                       of_node_put(node);
+                       continue;
+               }
+       }
+}
+
+static int tz1090_gpio_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct resource *res_regs;
+       struct tz1090_gpio priv;
+
+       if (!np) {
+               dev_err(&pdev->dev, "must be instantiated via devicetree\n");
+               return -ENOENT;
+       }
+
+       res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res_regs) {
+               dev_err(&pdev->dev, "cannot find registers resource\n");
+               return -ENOENT;
+       }
+
+       priv.dev = &pdev->dev;
+
+       /* Ioremap the registers */
+       priv.reg = devm_ioremap(&pdev->dev, res_regs->start,
+                                res_regs->end - res_regs->start);
+       if (!priv.reg) {
+               dev_err(&pdev->dev, "unable to ioremap registers\n");
+               return -ENOMEM;
+       }
+
+       /* Look for banks */
+       tz1090_gpio_register_banks(&priv);
+
+       return 0;
+}
+
+static struct of_device_id tz1090_gpio_of_match[] = {
+       { .compatible = "img,tz1090-gpio" },
+       { },
+};
+
+static struct platform_driver tz1090_gpio_driver = {
+       .driver = {
+               .name           = "tz1090-gpio",
+               .owner          = THIS_MODULE,
+               .of_match_table = tz1090_gpio_of_match,
+       },
+       .probe          = tz1090_gpio_probe,
+};
+
+static int __init tz1090_gpio_init(void)
+{
+       return platform_driver_register(&tz1090_gpio_driver);
+}
+subsys_initcall(tz1090_gpio_init);
index 6d0feb234d3c65ad8fb8115bd187811475f79a90..1a605f2a0f55f8fac1675dd18f37dae366215edc 100644 (file)
@@ -45,7 +45,7 @@ static void ucb1400_gpio_set(struct gpio_chip *gc, unsigned off, int val)
 
 static int ucb1400_gpio_probe(struct platform_device *dev)
 {
-       struct ucb1400_gpio *ucb = dev->dev.platform_data;
+       struct ucb1400_gpio *ucb = dev_get_platdata(&dev->dev);
        int err = 0;
 
        if (!(ucb && ucb->gpio_offset)) {
index 2a743e10ecb65336e59de61ef32586ba83639644..456000c5c4579fd380cb00c68b450b883e28dfb7 100644 (file)
@@ -246,7 +246,7 @@ static struct gpio_chip template_chip = {
 static int wm831x_gpio_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
        struct wm831x_gpio *wm831x_gpio;
        int ret;
 
index 0b598cf3df9dc6320b6047a15a4e7a9f73252e3b..fc49154be7b14a8bccf2b7aa58d078b7da939d22 100644 (file)
@@ -112,7 +112,7 @@ static struct gpio_chip template_chip = {
 static int wm8350_gpio_probe(struct platform_device *pdev)
 {
        struct wm8350 *wm8350 = dev_get_drvdata(pdev->dev.parent);
-       struct wm8350_platform_data *pdata = wm8350->dev->platform_data;
+       struct wm8350_platform_data *pdata = dev_get_platdata(wm8350->dev);
        struct wm8350_gpio_data *wm8350_gpio;
        int ret;
 
index ae409fd94af7421e9b2f42ddc4af73eeda6936a9..a53dbdefc7ee147c86255fa795c7bacfc1a42d0d 100644 (file)
@@ -248,7 +248,7 @@ static struct gpio_chip template_chip = {
 static int wm8994_gpio_probe(struct platform_device *pdev)
 {
        struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
-       struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+       struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev);
        struct wm8994_gpio *wm8994_gpio;
        int ret;
 
index 665f9530c950f96fd4cf54fb70c03edffbcc2ef2..0dfaf20e4dad4175fc7d5f49e6989d609876b123 100644 (file)
@@ -76,7 +76,8 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname,
        ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
                                         &gg_data.gpiospec);
        if (ret) {
-               pr_debug("%s: can't parse gpios property\n", __func__);
+               pr_debug("%s: can't parse gpios property of node '%s[%d]'\n",
+                       __func__, np->full_name, index);
                return ret;
        }
 
@@ -194,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 ff0fd655729f9e22d920d4efcb20777b93469df3..0dee0e0c247ae5fa2f121df234d09979dc00df74 100644 (file)
@@ -136,7 +136,7 @@ static struct gpio_desc *gpio_to_desc(unsigned gpio)
  */
 static int desc_to_gpio(const struct gpio_desc *desc)
 {
-       return desc->chip->base + gpio_chip_hwgpio(desc);
+       return desc - &gpio_desc[0];
 }
 
 
@@ -349,7 +349,7 @@ static ssize_t gpio_value_store(struct device *dev,
        else {
                long            value;
 
-               status = strict_strtol(buf, 0, &value);
+               status = kstrtol(buf, 0, &value);
                if (status == 0) {
                        if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
                                value = !value;
@@ -570,7 +570,7 @@ static ssize_t gpio_active_low_store(struct device *dev,
        } else {
                long            value;
 
-               status = strict_strtol(buf, 0, &value);
+               status = kstrtol(buf, 0, &value);
                if (status == 0)
                        status = sysfs_set_active_low(desc, dev, value != 0);
        }
@@ -652,7 +652,7 @@ static ssize_t export_store(struct class *class,
        struct gpio_desc        *desc;
        int                     status;
 
-       status = strict_strtol(buf, 0, &gpio);
+       status = kstrtol(buf, 0, &gpio);
        if (status < 0)
                goto done;
 
@@ -694,7 +694,7 @@ static ssize_t unexport_store(struct class *class,
        struct gpio_desc        *desc;
        int                     status;
 
-       status = strict_strtol(buf, 0, &gpio);
+       status = kstrtol(buf, 0, &gpio);
        if (status < 0)
                goto done;
 
@@ -1630,16 +1630,20 @@ static int gpiod_direction_input(struct gpio_desc *desc)
        int                     status = -EINVAL;
        int                     offset;
 
-       if (!desc) {
+       if (!desc || !desc->chip) {
                pr_warn("%s: invalid GPIO\n", __func__);
                return -EINVAL;
        }
 
+       chip = desc->chip;
+       if (!chip->get || !chip->direction_input) {
+               pr_warn("%s: missing get() or direction_input() operations\n",
+                       __func__);
+               return -EIO;
+       }
+
        spin_lock_irqsave(&gpio_lock, flags);
 
-       chip = desc->chip;
-       if (!chip || !chip->get || !chip->direction_input)
-               goto fail;
        status = gpio_ensure_requested(desc);
        if (status < 0)
                goto fail;
@@ -1691,7 +1695,7 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value)
        int                     status = -EINVAL;
        int offset;
 
-       if (!desc) {
+       if (!desc || !desc->chip) {
                pr_warn("%s: invalid GPIO\n", __func__);
                return -EINVAL;
        }
@@ -1704,11 +1708,15 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value)
        if (!value && test_bit(FLAG_OPEN_SOURCE,  &desc->flags))
                return gpiod_direction_input(desc);
 
+       chip = desc->chip;
+       if (!chip->set || !chip->direction_output) {
+               pr_warn("%s: missing set() or direction_output() operations\n",
+                       __func__);
+               return -EIO;
+       }
+
        spin_lock_irqsave(&gpio_lock, flags);
 
-       chip = desc->chip;
-       if (!chip || !chip->set || !chip->direction_output)
-               goto fail;
        status = gpio_ensure_requested(desc);
        if (status < 0)
                goto fail;
@@ -1757,6 +1765,9 @@ EXPORT_SYMBOL_GPL(gpio_direction_output);
  * gpio_set_debounce - sets @debounce time for a @gpio
  * @gpio: the gpio to set debounce time
  * @debounce: debounce time is microseconds
+ *
+ * returns -ENOTSUPP if the controller does not support setting
+ * debounce.
  */
 static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
 {
@@ -1765,16 +1776,19 @@ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
        int                     status = -EINVAL;
        int                     offset;
 
-       if (!desc) {
+       if (!desc || !desc->chip) {
                pr_warn("%s: invalid GPIO\n", __func__);
                return -EINVAL;
        }
 
-       spin_lock_irqsave(&gpio_lock, flags);
-
        chip = desc->chip;
-       if (!chip || !chip->set || !chip->set_debounce)
-               goto fail;
+       if (!chip->set || !chip->set_debounce) {
+               pr_debug("%s: missing set() or set_debounce() operations\n",
+                       __func__);
+               return -ENOTSUPP;
+       }
+
+       spin_lock_irqsave(&gpio_lock, flags);
 
        status = gpio_ensure_requested(desc);
        if (status < 0)
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 b4fb86d89850a31c3cc9424f4b4148831c59922f..224ff965bcf7de624c3b62b6db153bda090ea4a9 100644 (file)
 
 #include <drm/drmP.h>
 
+/******************************************************************/
+/** \name Context bitmap support */
+/*@{*/
+
 /**
  * Free a handle from the context bitmap.
  *
  * in drm_device::ctx_idr, while holding the drm_device::struct_mutex
  * lock.
  */
-static void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
+void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
 {
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return;
-
        mutex_lock(&dev->struct_mutex);
        idr_remove(&dev->ctx_idr, ctx_handle);
        mutex_unlock(&dev->struct_mutex);
 }
 
-/******************************************************************/
-/** \name Context bitmap support */
-/*@{*/
-
-void drm_legacy_ctxbitmap_release(struct drm_device *dev,
-                                 struct drm_file *file_priv)
-{
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return;
-
-       mutex_lock(&dev->ctxlist_mutex);
-       if (!list_empty(&dev->ctxlist)) {
-               struct drm_ctx_list *pos, *n;
-
-               list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
-                       if (pos->tag == file_priv &&
-                           pos->handle != DRM_KERNEL_CONTEXT) {
-                               if (dev->driver->context_dtor)
-                                       dev->driver->context_dtor(dev,
-                                                                 pos->handle);
-
-                               drm_ctxbitmap_free(dev, pos->handle);
-
-                               list_del(&pos->head);
-                               kfree(pos);
-                               --dev->ctx_count;
-                       }
-               }
-       }
-       mutex_unlock(&dev->ctxlist_mutex);
-}
-
 /**
  * Context bitmap allocation.
  *
@@ -121,12 +90,10 @@ static int drm_ctxbitmap_next(struct drm_device * dev)
  *
  * Initialise the drm_device::ctx_idr
  */
-void drm_legacy_ctxbitmap_init(struct drm_device * dev)
+int drm_ctxbitmap_init(struct drm_device * dev)
 {
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return;
-
        idr_init(&dev->ctx_idr);
+       return 0;
 }
 
 /**
@@ -137,7 +104,7 @@ void drm_legacy_ctxbitmap_init(struct drm_device * dev)
  * Free all idr members using drm_ctx_sarea_free helper function
  * while holding the drm_device::struct_mutex lock.
  */
-void drm_legacy_ctxbitmap_cleanup(struct drm_device * dev)
+void drm_ctxbitmap_cleanup(struct drm_device * dev)
 {
        mutex_lock(&dev->struct_mutex);
        idr_destroy(&dev->ctx_idr);
@@ -169,9 +136,6 @@ int drm_getsareactx(struct drm_device *dev, void *data,
        struct drm_local_map *map;
        struct drm_map_list *_entry;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        mutex_lock(&dev->struct_mutex);
 
        map = idr_find(&dev->ctx_idr, request->ctx_id);
@@ -216,9 +180,6 @@ int drm_setsareactx(struct drm_device *dev, void *data,
        struct drm_local_map *map = NULL;
        struct drm_map_list *r_list = NULL;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        mutex_lock(&dev->struct_mutex);
        list_for_each_entry(r_list, &dev->maplist, head) {
                if (r_list->map
@@ -319,9 +280,6 @@ int drm_resctx(struct drm_device *dev, void *data,
        struct drm_ctx ctx;
        int i;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        if (res->count >= DRM_RESERVED_CONTEXTS) {
                memset(&ctx, 0, sizeof(ctx));
                for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
@@ -352,9 +310,6 @@ int drm_addctx(struct drm_device *dev, void *data,
        struct drm_ctx_list *ctx_entry;
        struct drm_ctx *ctx = data;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        ctx->handle = drm_ctxbitmap_next(dev);
        if (ctx->handle == DRM_KERNEL_CONTEXT) {
                /* Skip kernel's context and get a new one. */
@@ -398,9 +353,6 @@ int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_ctx *ctx = data;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        /* This is 0, because we don't handle any context flags */
        ctx->flags = 0;
 
@@ -423,9 +375,6 @@ int drm_switchctx(struct drm_device *dev, void *data,
 {
        struct drm_ctx *ctx = data;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        DRM_DEBUG("%d\n", ctx->handle);
        return drm_context_switch(dev, dev->last_context, ctx->handle);
 }
@@ -446,9 +395,6 @@ int drm_newctx(struct drm_device *dev, void *data,
 {
        struct drm_ctx *ctx = data;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        DRM_DEBUG("%d\n", ctx->handle);
        drm_context_switch_complete(dev, file_priv, ctx->handle);
 
@@ -471,9 +417,6 @@ int drm_rmctx(struct drm_device *dev, void *data,
 {
        struct drm_ctx *ctx = data;
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
        DRM_DEBUG("%d\n", ctx->handle);
        if (ctx->handle != DRM_KERNEL_CONTEXT) {
                if (dev->driver->context_dtor)
index e572dd20bdee037fed5cdce356191ea84fd41e09..05ad9ba0a67e8ab4c9e79aade5b8ead441b7f3a8 100644 (file)
@@ -402,9 +402,16 @@ long drm_ioctl(struct file *filp,
                cmd = ioctl->cmd_drv;
        }
        else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {
+               u32 drv_size;
+
                ioctl = &drm_ioctls[nr];
-               cmd = ioctl->cmd;
+
+               drv_size = _IOC_SIZE(ioctl->cmd);
                usize = asize = _IOC_SIZE(cmd);
+               if (drv_size > asize)
+                       asize = drv_size;
+
+               cmd = ioctl->cmd;
        } else
                goto err_i1;
 
index 1688ff500513142d6d5072efb8061f1ae231bb3d..830f7501cb4d4f12fd914ec1bac6b0bbf7bae98d 100644 (file)
@@ -2925,6 +2925,8 @@ int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb)
                        /* Speaker Allocation Data Block */
                        if (dbl == 3) {
                                *sadb = kmalloc(dbl, GFP_KERNEL);
+                               if (!*sadb)
+                                       return -ENOMEM;
                                memcpy(*sadb, &db[1], dbl);
                                count = dbl;
                                break;
index 4be8e09a32ef730db4740f6f69e52f91ca829112..3f84277d7036b3f843120fb4145dc081010d3d0d 100644 (file)
@@ -439,7 +439,26 @@ int drm_release(struct inode *inode, struct file *filp)
        if (dev->driver->driver_features & DRIVER_GEM)
                drm_gem_release(dev, file_priv);
 
-       drm_legacy_ctxbitmap_release(dev, file_priv);
+       mutex_lock(&dev->ctxlist_mutex);
+       if (!list_empty(&dev->ctxlist)) {
+               struct drm_ctx_list *pos, *n;
+
+               list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
+                       if (pos->tag == file_priv &&
+                           pos->handle != DRM_KERNEL_CONTEXT) {
+                               if (dev->driver->context_dtor)
+                                       dev->driver->context_dtor(dev,
+                                                                 pos->handle);
+
+                               drm_ctxbitmap_free(dev, pos->handle);
+
+                               list_del(&pos->head);
+                               kfree(pos);
+                               --dev->ctx_count;
+                       }
+               }
+       }
+       mutex_unlock(&dev->ctxlist_mutex);
 
        mutex_lock(&dev->struct_mutex);
 
index e7eb0276f7f1968e6c71997eab517fd3a6746fac..39d864576be4a4d5f5957cdbf1e3112b1322a018 100644 (file)
@@ -292,7 +292,13 @@ int drm_fill_in_dev(struct drm_device *dev,
                        goto error_out_unreg;
        }
 
-       drm_legacy_ctxbitmap_init(dev);
+
+
+       retcode = drm_ctxbitmap_init(dev);
+       if (retcode) {
+               DRM_ERROR("Cannot allocate memory for context bitmap.\n");
+               goto error_out_unreg;
+       }
 
        if (driver->driver_features & DRIVER_GEM) {
                retcode = drm_gem_init(dev);
@@ -446,7 +452,7 @@ void drm_put_dev(struct drm_device *dev)
                drm_rmmap(dev, r_list->map);
        drm_ht_remove(&dev->map_hash);
 
-       drm_legacy_ctxbitmap_cleanup(dev);
+       drm_ctxbitmap_cleanup(dev);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                drm_put_minor(&dev->control);
index 4752f223e5b28a2fb793eb5b83be0fefb89a7ac2..45b6ef595965b7cb7391125d8b3a4caf2703b2b5 100644 (file)
@@ -56,7 +56,7 @@ config DRM_EXYNOS_IPP
 
 config DRM_EXYNOS_FIMC
        bool "Exynos DRM FIMC"
-       depends on DRM_EXYNOS_IPP && MFD_SYSCON && OF
+       depends on DRM_EXYNOS_IPP && MFD_SYSCON
        help
          Choose this option if you want to use Exynos FIMC for DRM.
 
index 3445a0f3a6b29dc6110d0e3a950a23de92a4098c..9c8088462c26f970d42b2fb40dae86490e51d3f6 100644 (file)
@@ -63,7 +63,8 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
                        return -ENOMEM;
                }
 
-               buf->kvaddr = dma_alloc_attrs(dev->dev, buf->size,
+               buf->kvaddr = (void __iomem *)dma_alloc_attrs(dev->dev,
+                                       buf->size,
                                        &buf->dma_addr, GFP_KERNEL,
                                        &buf->dma_attrs);
                if (!buf->kvaddr) {
@@ -90,9 +91,9 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
        }
 
        buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages);
-       if (!buf->sgt) {
+       if (IS_ERR(buf->sgt)) {
                DRM_ERROR("failed to get sg table.\n");
-               ret = -ENOMEM;
+               ret = PTR_ERR(buf->sgt);
                goto err_free_attrs;
        }
 
index 78e868bcf1ecc364638e4ce3343cc66f260599f0..e7c2f2d07f193b0393052be2e1bf32921b804da9 100644 (file)
@@ -99,12 +99,13 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
                if (is_drm_iommu_supported(dev)) {
                        unsigned int nr_pages = buffer->size >> PAGE_SHIFT;
 
-                       buffer->kvaddr = vmap(buffer->pages, nr_pages, VM_MAP,
+                       buffer->kvaddr = (void __iomem *) vmap(buffer->pages,
+                                       nr_pages, VM_MAP,
                                        pgprot_writecombine(PAGE_KERNEL));
                } else {
                        phys_addr_t dma_addr = buffer->dma_addr;
                        if (dma_addr)
-                               buffer->kvaddr = phys_to_virt(dma_addr);
+                               buffer->kvaddr = (void __iomem *)phys_to_virt(dma_addr);
                        else
                                buffer->kvaddr = (void __iomem *)NULL;
                }
index 92babac362ec0b85b6f1e52f05a6402411b43d1e..2db731f00930d7b28d85e124744423c8a37dd8b4 100644 (file)
@@ -204,6 +204,7 @@ static int psb_gtt_attach_pages(struct gtt_range *gt)
        if (IS_ERR(pages))
                return PTR_ERR(pages);
 
+       gt->npage = gt->gem.size / PAGE_SIZE;
        gt->pages = pages;
 
        return 0;
index b1f8fc69023fd97f9ee2ac28b3aaf35760aa3323..60e84043aa348fe3ec4293507edeb6b9477e3dc2 100644 (file)
@@ -707,8 +707,7 @@ tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
                reg_write(encoder, REG_VIP_CNTRL_2, priv->vip_cntrl_2);
                break;
        case DRM_MODE_DPMS_OFF:
-               /* disable audio and video ports */
-               reg_write(encoder, REG_ENA_AP, 0x00);
+               /* disable video ports */
                reg_write(encoder, REG_ENA_VP_0, 0x00);
                reg_write(encoder, REG_ENA_VP_1, 0x00);
                reg_write(encoder, REG_ENA_VP_2, 0x00);
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..d5c784d486714d4cc5b9e1a45c8b17fe13d51871 100644 (file)
@@ -1667,7 +1667,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 +1706,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..2ad27880cd047bc93cf119784895040eeafc3bae 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}
 };
 
@@ -601,6 +505,8 @@ static int i915_drm_freeze(struct drm_device *dev)
                intel_modeset_suspend_hw(dev);
        }
 
+       i915_gem_suspend_gtt_mappings(dev);
+
        i915_save_state(dev);
 
        intel_opregion_fini(dev);
@@ -744,7 +650,8 @@ static int i915_drm_thaw(struct drm_device *dev)
                mutex_lock(&dev->struct_mutex);
                i915_gem_restore_gtt_mappings(dev);
                mutex_unlock(&dev->struct_mutex);
-       }
+       } else if (drm_core_check_feature(dev, DRIVER_MODESET))
+               i915_check_and_clear_faults(dev);
 
        __i915_drm_thaw(dev);
 
index 52a3785a3fdfa59fbab49f9098f8448418ff2155..ab0f2c0a440c6a4543a59d81282c4ab21316b2cc 100644 (file)
@@ -497,10 +497,12 @@ struct i915_address_space {
 
        /* FIXME: Need a more generic return type */
        gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr,
-                                    enum i915_cache_level level);
+                                    enum i915_cache_level level,
+                                    bool valid); /* Create a valid PTE */
        void (*clear_range)(struct i915_address_space *vm,
                            unsigned int first_entry,
-                           unsigned int num_entries);
+                           unsigned int num_entries,
+                           bool use_scratch);
        void (*insert_entries)(struct i915_address_space *vm,
                               struct sg_table *st,
                               unsigned int first_entry,
@@ -1236,6 +1238,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 */
@@ -2058,6 +2067,8 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
 void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
                              struct drm_i915_gem_object *obj);
 
+void i915_check_and_clear_faults(struct drm_device *dev);
+void i915_gem_suspend_gtt_mappings(struct drm_device *dev);
 void i915_gem_restore_gtt_mappings(struct drm_device *dev);
 int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj);
 void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
index 2d1cb10d846f376073d2da03e9c974300ee98f88..cdfb9da0e4ce944529a329ce29f92d391e19973a 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)
@@ -1390,14 +1392,11 @@ out:
                if (i915_terminally_wedged(&dev_priv->gpu_error))
                        return VM_FAULT_SIGBUS;
        case -EAGAIN:
-               /* Give the error handler a chance to run and move the
-                * objects off the GPU active list. Next time we service the
-                * fault, we should be able to transition the page into the
-                * GTT without touching the GPU (and so avoid further
-                * EIO/EGAIN). If the GPU is wedged, then there is no issue
-                * with coherency, just lost writes.
+               /*
+                * EAGAIN means the gpu is hung and we'll wait for the error
+                * handler to reset everything when re-faulting in
+                * i915_mutex_lock_interruptible.
                 */
-               set_need_resched();
        case 0:
        case -ERESTARTSYS:
        case -EINTR:
@@ -1695,6 +1694,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 +1709,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 +1768,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 +1811,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 +4562,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 +4786,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,9 +4795,8 @@ 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))
@@ -4772,31 +4808,22 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
                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 +4887,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 SHRINK_STOP;
+
+               if (dev_priv->mm.shrinker_no_lock_stealing)
+                       return SHRINK_STOP;
+
+               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 212f6d8c35ec6593cc54957ecd24445196d26657..1f7b4caefb6e0776bf61d78af519812765b37741 100644 (file)
 #define HSW_WT_ELLC_LLC_AGE0           HSW_CACHEABILITY_CONTROL(0x6)
 
 static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level)
+                                    enum i915_cache_level level,
+                                    bool valid)
 {
-       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -79,9 +80,10 @@ static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
 }
 
 static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level)
+                                    enum i915_cache_level level,
+                                    bool valid)
 {
-       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -105,9 +107,10 @@ static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
 #define BYT_PTE_SNOOPED_BY_CPU_CACHES  (1 << 2)
 
 static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level)
+                                    enum i915_cache_level level,
+                                    bool valid)
 {
-       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        /* Mark the page as writeable.  Other platforms don't have a
@@ -122,9 +125,10 @@ static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
 }
 
 static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr,
-                                    enum i915_cache_level level)
+                                    enum i915_cache_level level,
+                                    bool valid)
 {
-       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= HSW_PTE_ADDR_ENCODE(addr);
 
        if (level != I915_CACHE_NONE)
@@ -134,9 +138,10 @@ static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr,
 }
 
 static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
-                                     enum i915_cache_level level)
+                                     enum i915_cache_level level,
+                                     bool valid)
 {
-       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= HSW_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
@@ -236,7 +241,8 @@ static int gen6_ppgtt_enable(struct drm_device *dev)
 /* PPGTT support for Sandybdrige/Gen6 and later */
 static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
                                   unsigned first_entry,
-                                  unsigned num_entries)
+                                  unsigned num_entries,
+                                  bool use_scratch)
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
@@ -245,7 +251,7 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
        unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
        unsigned last_pte, i;
 
-       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC);
+       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true);
 
        while (num_entries) {
                last_pte = first_pte + num_entries;
@@ -282,7 +288,7 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
                dma_addr_t page_addr;
 
                page_addr = sg_page_iter_dma_address(&sg_iter);
-               pt_vaddr[act_pte] = vm->pte_encode(page_addr, cache_level);
+               pt_vaddr[act_pte] = vm->pte_encode(page_addr, cache_level, true);
                if (++act_pte == I915_PPGTT_PT_ENTRIES) {
                        kunmap_atomic(pt_vaddr);
                        act_pt++;
@@ -367,7 +373,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
        }
 
        ppgtt->base.clear_range(&ppgtt->base, 0,
-                               ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES);
+                               ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES, true);
 
        ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t);
 
@@ -444,7 +450,8 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
 {
        ppgtt->base.clear_range(&ppgtt->base,
                                i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT,
-                               obj->base.size >> PAGE_SHIFT);
+                               obj->base.size >> PAGE_SHIFT,
+                               true);
 }
 
 extern int intel_iommu_gfx_mapped;
@@ -485,15 +492,65 @@ static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible)
                dev_priv->mm.interruptible = interruptible;
 }
 
+void i915_check_and_clear_faults(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
+       int i;
+
+       if (INTEL_INFO(dev)->gen < 6)
+               return;
+
+       for_each_ring(ring, dev_priv, i) {
+               u32 fault_reg;
+               fault_reg = I915_READ(RING_FAULT_REG(ring));
+               if (fault_reg & RING_FAULT_VALID) {
+                       DRM_DEBUG_DRIVER("Unexpected fault\n"
+                                        "\tAddr: 0x%08lx\\n"
+                                        "\tAddress space: %s\n"
+                                        "\tSource ID: %d\n"
+                                        "\tType: %d\n",
+                                        fault_reg & PAGE_MASK,
+                                        fault_reg & RING_FAULT_GTTSEL_MASK ? "GGTT" : "PPGTT",
+                                        RING_FAULT_SRCID(fault_reg),
+                                        RING_FAULT_FAULT_TYPE(fault_reg));
+                       I915_WRITE(RING_FAULT_REG(ring),
+                                  fault_reg & ~RING_FAULT_VALID);
+               }
+       }
+       POSTING_READ(RING_FAULT_REG(&dev_priv->ring[RCS]));
+}
+
+void i915_gem_suspend_gtt_mappings(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /* Don't bother messing with faults pre GEN6 as we have little
+        * documentation supporting that it's a good idea.
+        */
+       if (INTEL_INFO(dev)->gen < 6)
+               return;
+
+       i915_check_and_clear_faults(dev);
+
+       dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
+                                      dev_priv->gtt.base.start / PAGE_SIZE,
+                                      dev_priv->gtt.base.total / PAGE_SIZE,
+                                      false);
+}
+
 void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj;
 
+       i915_check_and_clear_faults(dev);
+
        /* First fill our portion of the GTT with scratch pages */
        dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
                                       dev_priv->gtt.base.start / PAGE_SIZE,
-                                      dev_priv->gtt.base.total / PAGE_SIZE);
+                                      dev_priv->gtt.base.total / PAGE_SIZE,
+                                      true);
 
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                i915_gem_clflush_object(obj, obj->pin_display);
@@ -536,7 +593,7 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
 
        for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
                addr = sg_page_iter_dma_address(&sg_iter);
-               iowrite32(vm->pte_encode(addr, level), &gtt_entries[i]);
+               iowrite32(vm->pte_encode(addr, level, true), &gtt_entries[i]);
                i++;
        }
 
@@ -548,7 +605,7 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
         */
        if (i != 0)
                WARN_ON(readl(&gtt_entries[i-1]) !=
-                       vm->pte_encode(addr, level));
+                       vm->pte_encode(addr, level, true));
 
        /* This next bit makes the above posting read even more important. We
         * want to flush the TLBs only after we're certain all the PTE updates
@@ -560,7 +617,8 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
 
 static void gen6_ggtt_clear_range(struct i915_address_space *vm,
                                  unsigned int first_entry,
-                                 unsigned int num_entries)
+                                 unsigned int num_entries,
+                                 bool use_scratch)
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        gen6_gtt_pte_t scratch_pte, __iomem *gtt_base =
@@ -573,7 +631,8 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
                 first_entry, num_entries, max_entries))
                num_entries = max_entries;
 
-       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC);
+       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, use_scratch);
+
        for (i = 0; i < num_entries; i++)
                iowrite32(scratch_pte, &gtt_base[i]);
        readl(gtt_base);
@@ -594,7 +653,8 @@ static void i915_ggtt_insert_entries(struct i915_address_space *vm,
 
 static void i915_ggtt_clear_range(struct i915_address_space *vm,
                                  unsigned int first_entry,
-                                 unsigned int num_entries)
+                                 unsigned int num_entries,
+                                 bool unused)
 {
        intel_gtt_clear_range(first_entry, num_entries);
 }
@@ -622,7 +682,8 @@ void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
 
        dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
                                       entry,
-                                      obj->base.size >> PAGE_SHIFT);
+                                      obj->base.size >> PAGE_SHIFT,
+                                      true);
 
        obj->has_global_gtt_mapping = 0;
 }
@@ -709,11 +770,11 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
                const unsigned long count = (hole_end - hole_start) / PAGE_SIZE;
                DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n",
                              hole_start, hole_end);
-               ggtt_vm->clear_range(ggtt_vm, hole_start / PAGE_SIZE, count);
+               ggtt_vm->clear_range(ggtt_vm, hole_start / PAGE_SIZE, count, true);
        }
 
        /* And finally clear the reserved guard page */
-       ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1);
+       ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1, true);
 }
 
 static bool
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..dae364f0028cc94d58f87613449b41d7620d7f29 100644 (file)
@@ -143,8 +143,10 @@ static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
 
        /* Seek the first printf which is hits start position */
        if (e->pos < e->start) {
-               len = vsnprintf(NULL, 0, f, args);
-               if (!__i915_error_seek(e, len))
+               va_list tmp;
+
+               va_copy(tmp, args);
+               if (!__i915_error_seek(e, vsnprintf(NULL, 0, f, tmp)))
                        return;
        }
 
@@ -641,7 +643,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..4b91228fd9bd8e50e1319816a9fe53b6f166ec68 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)
@@ -1464,6 +1469,34 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        return ret;
 }
 
+static void i915_error_wake_up(struct drm_i915_private *dev_priv,
+                              bool reset_completed)
+{
+       struct intel_ring_buffer *ring;
+       int i;
+
+       /*
+        * Notify all waiters for GPU completion events that reset state has
+        * been changed, and that they need to restart their wait after
+        * checking for potential errors (and bail out to drop locks if there is
+        * a gpu reset pending so that i915_error_work_func can acquire them).
+        */
+
+       /* Wake up __wait_seqno, potentially holding dev->struct_mutex. */
+       for_each_ring(ring, dev_priv, i)
+               wake_up_all(&ring->irq_queue);
+
+       /* Wake up intel_crtc_wait_for_pending_flips, holding crtc->mutex. */
+       wake_up_all(&dev_priv->pending_flip_queue);
+
+       /*
+        * Signal tasks blocked in i915_gem_wait_for_error that the pending
+        * reset state is cleared.
+        */
+       if (reset_completed)
+               wake_up_all(&dev_priv->gpu_error.reset_queue);
+}
+
 /**
  * i915_error_work_func - do process context error handling work
  * @work: work struct
@@ -1478,11 +1511,10 @@ static void i915_error_work_func(struct work_struct *work)
        drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t,
                                                    gpu_error);
        struct drm_device *dev = dev_priv->dev;
-       struct intel_ring_buffer *ring;
        char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
        char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
        char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
-       int i, ret;
+       int ret;
 
        kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
 
@@ -1501,8 +1533,16 @@ static void i915_error_work_func(struct work_struct *work)
                kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE,
                                   reset_event);
 
+               /*
+                * All state reset _must_ be completed before we update the
+                * reset counter, for otherwise waiters might miss the reset
+                * pending state and not properly drop locks, resulting in
+                * deadlocks with the reset work.
+                */
                ret = i915_reset(dev);
 
+               intel_display_handle_reset(dev);
+
                if (ret == 0) {
                        /*
                         * After all the gem state is reset, increment the reset
@@ -1523,12 +1563,11 @@ static void i915_error_work_func(struct work_struct *work)
                        atomic_set(&error->reset_counter, I915_WEDGED);
                }
 
-               for_each_ring(ring, dev_priv, i)
-                       wake_up_all(&ring->irq_queue);
-
-               intel_display_handle_reset(dev);
-
-               wake_up_all(&dev_priv->gpu_error.reset_queue);
+               /*
+                * Note: The wake_up also serves as a memory barrier so that
+                * waiters see the update value of the reset counter atomic_t.
+                */
+               i915_error_wake_up(dev_priv, true);
        }
 }
 
@@ -1637,8 +1676,6 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
 void i915_handle_error(struct drm_device *dev, bool wedged)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *ring;
-       int i;
 
        i915_capture_error_state(dev);
        i915_report_and_clear_eir(dev);
@@ -1648,14 +1685,28 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
                                &dev_priv->gpu_error.reset_counter);
 
                /*
-                * Wakeup waiting processes so that the reset work item
-                * doesn't deadlock trying to grab various locks.
+                * Wakeup waiting processes so that the reset work function
+                * i915_error_work_func doesn't deadlock trying to grab various
+                * locks. By bumping the reset counter first, the woken
+                * processes will see a reset in progress and back off,
+                * releasing their locks and then wait for the reset completion.
+                * We must do this for _all_ gpu waiters that might hold locks
+                * that the reset work needs to acquire.
+                *
+                * Note: The wake_up serves as the required memory barrier to
+                * ensure that the waiters see the updated value of the reset
+                * counter atomic_t.
                 */
-               for_each_ring(ring, dev_priv, i)
-                       wake_up_all(&ring->irq_queue);
+               i915_error_wake_up(dev_priv, false);
        }
 
-       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 +2078,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..ef9b35479f0136d0cb23ec7f6eb2bb59afa85e46 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   ARB_MODE_SWIZZLE_IVB (1<<5)
 #define RENDER_HWS_PGA_GEN7    (0x04080)
 #define RING_FAULT_REG(ring)   (0x4094 + 0x100*(ring)->id)
+#define   RING_FAULT_GTTSEL_MASK (1<<11)
+#define   RING_FAULT_SRCID(x)  ((x >> 3) & 0xff)
+#define   RING_FAULT_FAULT_TYPE(x) ((x >> 1) & 0x3)
+#define   RING_FAULT_VALID     (1<<0)
 #define DONE_REG               0x40b0
 #define BSD_HWS_PGA_GEN7       (0x04180)
 #define BLT_HWS_PGA_GEN7       (0x04280)
 #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
 #define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG         0x9030
 #define  GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB      (1<<11)
 
+#define HSW_SCRATCH1                           0xb038
+#define  HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE  (1<<27)
+
 #define HSW_FUSE_STRAP         0x42014
 #define  HSW_CDCLK_LIMIT       (1 << 24)
 
 #define FDI_RX_CHICKEN(pipe) _PIPE(pipe, _FDI_RXA_CHICKEN, _FDI_RXB_CHICKEN)
 
 #define SOUTH_DSPCLK_GATE_D    0xc2020
+#define  PCH_DPLUNIT_CLOCK_GATE_DISABLE (1<<30)
 #define  PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29)
+#define  PCH_CPUNIT_CLOCK_GATE_DISABLE (1<<14)
 #define  PCH_LP_PARTITION_LEVEL_DISABLE  (1<<12)
 
 /* CPU: FDI_TX */
 #define GEN7_ROW_CHICKEN2_GT2          0xf4f4
 #define   DOP_CLOCK_GATING_DISABLE     (1<<0)
 
+#define HSW_ROW_CHICKEN3               0xe49c
+#define  HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE    (1 << 6)
+
 #define G4X_AUD_VID_DID                        (dev_priv->info->display_mmio_offset + 0x62020)
 #define INTEL_AUDIO_DEVCL              0x808629FB
 #define INTEL_AUDIO_DEVBLC             0x80862801
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 63aca49d11a843a6ad6ae1a62dc11d0b3bfd470c..63de2701b97403a82ffd221424d5b5b9acda5843 100644 (file)
@@ -778,7 +778,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
                        /* Can only use the always-on power well for eDP when
                         * not using the panel fitter, and when not using motion
                          * blur mitigation (which we don't support). */
-                       if (intel_crtc->config.pch_pfit.size)
+                       if (intel_crtc->config.pch_pfit.enabled)
                                temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
                        else
                                temp |= TRANS_DDI_EDP_INPUT_A_ON;
index 38452d82ac7dc4d57c603151de925d8aecf63ae6..581fb4b2f76637694877a2c4401acd2f35ade58c 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);
 
@@ -2247,7 +2249,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                I915_WRITE(PIPESRC(intel_crtc->pipe),
                           ((crtc->mode.hdisplay - 1) << 16) |
                           (crtc->mode.vdisplay - 1));
-               if (!intel_crtc->config.pch_pfit.size &&
+               if (!intel_crtc->config.pch_pfit.enabled &&
                    (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
                     intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
                        I915_WRITE(PF_CTL(intel_crtc->pipe), 0);
@@ -3201,7 +3203,7 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe = crtc->pipe;
 
-       if (crtc->config.pch_pfit.size) {
+       if (crtc->config.pch_pfit.enabled) {
                /* Force use of hard-coded filter coefficients
                 * as some pre-programmed values are broken,
                 * e.g. x201.
@@ -3426,7 +3428,7 @@ static void ironlake_pfit_disable(struct intel_crtc *crtc)
 
        /* To avoid upsetting the power well on haswell only disable the pfit if
         * it's in use. The hw state code will make sure we get this right. */
-       if (crtc->config.pch_pfit.size) {
+       if (crtc->config.pch_pfit.enabled) {
                I915_WRITE(PF_CTL(pipe), 0);
                I915_WRITE(PF_WIN_POS(pipe), 0);
                I915_WRITE(PF_WIN_SZ(pipe), 0);
@@ -3939,8 +3941,6 @@ static void intel_connector_check_state(struct intel_connector *connector)
  * consider. */
 void intel_connector_dpms(struct drm_connector *connector, int mode)
 {
-       struct intel_encoder *encoder = intel_attached_encoder(connector);
-
        /* All the simple cases only support two dpms states. */
        if (mode != DRM_MODE_DPMS_ON)
                mode = DRM_MODE_DPMS_OFF;
@@ -3951,10 +3951,8 @@ void intel_connector_dpms(struct drm_connector *connector, int mode)
        connector->dpms = mode;
 
        /* Only need to change hw state when actually enabled */
-       if (encoder->base.crtc)
-               intel_encoder_dpms(encoder, mode);
-       else
-               WARN_ON(encoder->connectors_active != false);
+       if (connector->encoder)
+               intel_encoder_dpms(to_intel_encoder(connector->encoder), mode);
 
        intel_modeset_check_state(connector->dev);
 }
@@ -4773,6 +4771,10 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
 
        pipeconf = 0;
 
+       if (dev_priv->quirks & QUIRK_PIPEA_FORCE &&
+           I915_READ(PIPECONF(intel_crtc->pipe)) & PIPECONF_ENABLE)
+               pipeconf |= PIPECONF_ENABLE;
+
        if (intel_crtc->pipe == 0 && INTEL_INFO(dev)->gen < 4) {
                /* Enable pixel doubling when the dot clock is > 90% of the (display)
                 * core speed.
@@ -4875,9 +4877,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
-       /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc, true);
-
        if (is_lvds && dev_priv->lvds_downclock_avail) {
                /*
                 * Ensure we match the reduced clock's P to the target clock.
@@ -5766,9 +5765,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                intel_crtc->config.dpll.p2 = clock.p2;
        }
 
-       /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc, true);
-
        /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
        if (intel_crtc->config.has_pch_encoder) {
                fp = i9xx_dpll_compute_fp(&intel_crtc->config.dpll);
@@ -5857,6 +5853,7 @@ static void ironlake_get_pfit_config(struct intel_crtc *crtc,
        tmp = I915_READ(PF_CTL(crtc->pipe));
 
        if (tmp & PF_ENABLE) {
+               pipe_config->pch_pfit.enabled = true;
                pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe));
                pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe));
 
@@ -6234,7 +6231,7 @@ static void haswell_modeset_global_resources(struct drm_device *dev)
                if (!crtc->base.enabled)
                        continue;
 
-               if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.size ||
+               if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.enabled ||
                    crtc->config.cpu_transcoder != TRANSCODER_EDP)
                        enable = true;
        }
@@ -6257,9 +6254,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
        if (!intel_ddi_pll_mode_set(crtc))
                return -EINVAL;
 
-       /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc, true);
-
        if (intel_crtc->config.has_dp_encoder)
                intel_dp_set_m_n(intel_crtc);
 
@@ -6492,15 +6486,15 @@ static void haswell_write_eld(struct drm_connector *connector,
 
        /* Set ELD valid state */
        tmp = I915_READ(aud_cntrl_st2);
-       DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%8x\n", tmp);
+       DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%08x\n", tmp);
        tmp |= (AUDIO_ELD_VALID_A << (pipe * 4));
        I915_WRITE(aud_cntrl_st2, tmp);
        tmp = I915_READ(aud_cntrl_st2);
-       DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%8x\n", tmp);
+       DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%08x\n", tmp);
 
        /* Enable HDMI mode */
        tmp = I915_READ(aud_config);
-       DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%8x\n", tmp);
+       DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%08x\n", tmp);
        /* clear N_programing_enable and N_value_index */
        tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE);
        I915_WRITE(aud_config, tmp);
@@ -6762,8 +6756,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;
@@ -6933,7 +6929,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        intel_crtc->cursor_width = width;
        intel_crtc->cursor_height = height;
 
-       intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
+       if (intel_crtc->active)
+               intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
 
        return 0;
 fail_unpin:
@@ -6952,7 +6949,8 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        intel_crtc->cursor_x = x;
        intel_crtc->cursor_y = y;
 
-       intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
+       if (intel_crtc->active)
+               intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
 
        return 0;
 }
@@ -7309,8 +7307,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 +7825,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 +7833,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 +7861,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);
@@ -8180,9 +8199,10 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
                      pipe_config->gmch_pfit.control,
                      pipe_config->gmch_pfit.pgm_ratios,
                      pipe_config->gmch_pfit.lvds_border_bits);
-       DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x\n",
+       DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x, %s\n",
                      pipe_config->pch_pfit.pos,
-                     pipe_config->pch_pfit.size);
+                     pipe_config->pch_pfit.size,
+                     pipe_config->pch_pfit.enabled ? "enabled" : "disabled");
        DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled);
 }
 
@@ -8578,8 +8598,11 @@ intel_pipe_config_compare(struct drm_device *dev,
        if (INTEL_INFO(dev)->gen < 4)
                PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios);
        PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits);
-       PIPE_CONF_CHECK_I(pch_pfit.pos);
-       PIPE_CONF_CHECK_I(pch_pfit.size);
+       PIPE_CONF_CHECK_I(pch_pfit.enabled);
+       if (current_config->pch_pfit.enabled) {
+               PIPE_CONF_CHECK_I(pch_pfit.pos);
+               PIPE_CONF_CHECK_I(pch_pfit.size);
+       }
 
        PIPE_CONF_CHECK_I(ips_enabled);
 
index 2151d13772b8248cf1f6d6d71c2720fa074fe435..2c555f91bfae076688fe07e1694c75932a9c97d2 100644 (file)
@@ -588,7 +588,18 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                        DRM_DEBUG_KMS("aux_ch native nack\n");
                        return -EREMOTEIO;
                case AUX_NATIVE_REPLY_DEFER:
-                       udelay(100);
+                       /*
+                        * For now, just give more slack to branch devices. We
+                        * could check the DPCD for I2C bit rate capabilities,
+                        * and if available, adjust the interval. We could also
+                        * be more careful with DP-to-Legacy adapters where a
+                        * long legacy cable may force very low I2C bit rates.
+                        */
+                       if (intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+                           DP_DWN_STRM_PORT_PRESENT)
+                               usleep_range(500, 600);
+                       else
+                               usleep_range(300, 400);
                        continue;
                default:
                        DRM_ERROR("aux_ch invalid native reply 0x%02x\n",
@@ -1456,7 +1467,7 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
 
        /* Avoid continuous PSR exit by masking memup and hpd */
        I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP |
-                  EDP_PSR_DEBUG_MASK_HPD);
+                  EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
 
        intel_dp->psr_setup_done = true;
 }
index 176080822a74d1e76d099615cb218c9a93736300..9b7b68fd5d47cf6c979c8fdffd412d8381aabc0e 100644 (file)
@@ -280,6 +280,7 @@ struct intel_crtc_config {
        struct {
                u32 pos;
                u32 size;
+               bool enabled;
        } pch_pfit;
 
        /* FDI configuration, only valid if has_pch_encoder is set. */
@@ -551,7 +552,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,
index 406303b509c1c0afeed4be9379060e5417e212e0..7fa7df546c1ee6e36e119af34d6e79a9d7015e82 100644 (file)
@@ -263,6 +263,8 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
                C(vtotal);
                C(clock);
 #undef C
+
+               drm_mode_set_crtcinfo(adjusted_mode, 0);
        }
 
        if (intel_dvo->dev.dev_ops->mode_fixup)
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..293564a2896a19038cc87ecba7648bce511388d2 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 */
@@ -120,6 +112,7 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
 done:
        pipe_config->pch_pfit.pos = (x << 16) | y;
        pipe_config->pch_pfit.size = (width << 16) | height;
+       pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
 }
 
 static void
index 46056820d1d2200db076c2e5f3291fdde1068915..26c2ea3e985c22d7011e68f3e73d14fa8e896131 100644 (file)
@@ -2096,16 +2096,16 @@ static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev,
                                    struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       uint32_t pixel_rate, pfit_size;
+       uint32_t pixel_rate;
 
        pixel_rate = intel_crtc->config.adjusted_mode.clock;
 
        /* We only use IF-ID interlacing. If we ever use PF-ID we'll need to
         * adjust the pixel_rate here. */
 
-       pfit_size = intel_crtc->config.pch_pfit.size;
-       if (pfit_size) {
+       if (intel_crtc->config.pch_pfit.enabled) {
                uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
+               uint32_t pfit_size = intel_crtc->config.pch_pfit.size;
 
                pipe_w = intel_crtc->config.requested_mode.hdisplay;
                pipe_h = intel_crtc->config.requested_mode.vdisplay;
@@ -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)
@@ -3854,8 +3864,6 @@ static void valleyview_enable_rps(struct drm_device *dev)
                                      dev_priv->rps.rpe_delay),
                         dev_priv->rps.rpe_delay);
 
-       INIT_DELAYED_WORK(&dev_priv->rps.vlv_work, vlv_rps_timer_work);
-
        valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay);
 
        gen6_enable_rps_interrupts(dev);
@@ -4751,7 +4759,9 @@ static void cpt_init_clock_gating(struct drm_device *dev)
         * gating for the panel power sequencer or it will fail to
         * start up when no ports are active.
         */
-       I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+       I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE |
+                  PCH_DPLUNIT_CLOCK_GATE_DISABLE |
+                  PCH_CPUNIT_CLOCK_GATE_DISABLE);
        I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
                   DPLS_EDP_PPS_FIX_DIS);
        /* The below fixes the weird display corruption, a few pixels shifted
@@ -4945,13 +4955,16 @@ static void haswell_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER,
                        GEN7_WA_L3_CHICKEN_MODE);
 
+       /* L3 caching of data atomics doesn't work -- disable it. */
+       I915_WRITE(HSW_SCRATCH1, HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE);
+       I915_WRITE(HSW_ROW_CHICKEN3,
+                  _MASKED_BIT_ENABLE(HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE));
+
        /* This is required by WaCatErrorRejectionIssue:hsw */
        I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
                        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);
 
@@ -5673,5 +5686,7 @@ void intel_pm_init(struct drm_device *dev)
 
        INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
                          intel_gen6_powersave_work);
+
+       INIT_DELAYED_WORK(&dev_priv->rps.vlv_work, vlv_rps_timer_work);
 }
 
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..49482fd5b76c6cad80298d2d2f67c0050c73a93d 100644 (file)
@@ -788,6 +788,8 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
        uint16_t h_sync_offset, v_sync_offset;
        int mode_clock;
 
+       memset(dtd, 0, sizeof(*dtd));
+
        width = mode->hdisplay;
        height = mode->vdisplay;
 
@@ -830,44 +832,51 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
        if (mode->flags & DRM_MODE_FLAG_PVSYNC)
                dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE;
 
-       dtd->part2.sdvo_flags = 0;
        dtd->part2.v_sync_off_high = v_sync_offset & 0xc0;
-       dtd->part2.reserved = 0;
 }
 
-static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
+static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode *pmode,
                                         const struct intel_sdvo_dtd *dtd)
 {
-       mode->hdisplay = dtd->part1.h_active;
-       mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
-       mode->hsync_start = mode->hdisplay + dtd->part2.h_sync_off;
-       mode->hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
-       mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width;
-       mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
-       mode->htotal = mode->hdisplay + dtd->part1.h_blank;
-       mode->htotal += (dtd->part1.h_high & 0xf) << 8;
-
-       mode->vdisplay = dtd->part1.v_active;
-       mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
-       mode->vsync_start = mode->vdisplay;
-       mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
-       mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
-       mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0;
-       mode->vsync_end = mode->vsync_start +
+       struct drm_display_mode mode = {};
+
+       mode.hdisplay = dtd->part1.h_active;
+       mode.hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
+       mode.hsync_start = mode.hdisplay + dtd->part2.h_sync_off;
+       mode.hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
+       mode.hsync_end = mode.hsync_start + dtd->part2.h_sync_width;
+       mode.hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
+       mode.htotal = mode.hdisplay + dtd->part1.h_blank;
+       mode.htotal += (dtd->part1.h_high & 0xf) << 8;
+
+       mode.vdisplay = dtd->part1.v_active;
+       mode.vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
+       mode.vsync_start = mode.vdisplay;
+       mode.vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
+       mode.vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
+       mode.vsync_start += dtd->part2.v_sync_off_high & 0xc0;
+       mode.vsync_end = mode.vsync_start +
                (dtd->part2.v_sync_off_width & 0xf);
-       mode->vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;
-       mode->vtotal = mode->vdisplay + dtd->part1.v_blank;
-       mode->vtotal += (dtd->part1.v_high & 0xf) << 8;
+       mode.vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;
+       mode.vtotal = mode.vdisplay + dtd->part1.v_blank;
+       mode.vtotal += (dtd->part1.v_high & 0xf) << 8;
 
-       mode->clock = dtd->part1.clock * 10;
+       mode.clock = dtd->part1.clock * 10;
 
-       mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
        if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE)
-               mode->flags |= DRM_MODE_FLAG_INTERLACE;
+               mode.flags |= DRM_MODE_FLAG_INTERLACE;
        if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
-               mode->flags |= DRM_MODE_FLAG_PHSYNC;
+               mode.flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               mode.flags |= DRM_MODE_FLAG_NHSYNC;
        if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
-               mode->flags |= DRM_MODE_FLAG_PVSYNC;
+               mode.flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               mode.flags |= DRM_MODE_FLAG_NVSYNC;
+
+       drm_mode_set_crtcinfo(&mode, 0);
+
+       drm_mode_copy(pmode, &mode);
 }
 
 static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
@@ -1151,11 +1160,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 +1221,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 +1262,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 +1274,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 f2c6d7909ae2d66ffa73ebe77d7c3b06d46403f7..dd6f84bf6c220e94c7f50e1d38ca7fea9f11cecb 100644 (file)
@@ -916,6 +916,14 @@ intel_tv_compute_config(struct intel_encoder *encoder,
        DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
        pipe_config->pipe_bpp = 8*3;
 
+       /* TV has it's own notion of sync and other mode flags, so clear them. */
+       pipe_config->adjusted_mode.flags = 0;
+
+       /*
+        * FIXME: We don't check whether the input mode is actually what we want
+        * or whether userspace is doing something stupid.
+        */
+
        return true;
 }
 
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 a60584763b61dde085f39c8058e4cb6900e2bace..a0b9d8a95b16c17ad6b11ae1b6da662e80484b04 100644 (file)
@@ -124,6 +124,8 @@ void adreno_recover(struct msm_gpu *gpu)
 
        /* reset completed fence seqno, just discard anything pending: */
        adreno_gpu->memptrs->fence = gpu->submitted_fence;
+       adreno_gpu->memptrs->rptr  = 0;
+       adreno_gpu->memptrs->wptr  = 0;
 
        gpu->funcs->pm_resume(gpu);
        ret = gpu->funcs->hw_init(gpu);
@@ -229,7 +231,7 @@ void adreno_idle(struct msm_gpu *gpu)
                        return;
        } while(time_before(jiffies, t));
 
-       DRM_ERROR("timeout waiting for %s to drain ringbuffer!\n", gpu->name);
+       DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name);
 
        /* TODO maybe we need to reset GPU here to recover from hang? */
 }
@@ -256,11 +258,17 @@ void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
        uint32_t freedwords;
+       unsigned long t = jiffies + ADRENO_IDLE_TIMEOUT;
        do {
                uint32_t size = gpu->rb->size / 4;
                uint32_t wptr = get_wptr(gpu->rb);
                uint32_t rptr = adreno_gpu->memptrs->rptr;
                freedwords = (rptr + (size - 1) - wptr) % size;
+
+               if (time_after(jiffies, t)) {
+                       DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name);
+                       break;
+               }
        } while(freedwords < ndwords);
 }
 
index 5db5bbaedae21d64b9764fc8d009dfa86b862543..bc7fd11ad8be4e7d4785d0f696d128220f25b7ca 100644 (file)
@@ -19,8 +19,6 @@
 #include "msm_drv.h"
 #include "mdp4_kms.h"
 
-#include <mach/iommu.h>
-
 static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev);
 
 static int mdp4_hw_init(struct msm_kms *kms)
index 864c9773636baf6aa7173c6b16a5f81841a2b922..b3a2f16290417cb055a8d7d89dc8f3f876b3a090 100644 (file)
@@ -18,8 +18,6 @@
 #include "msm_drv.h"
 #include "msm_gpu.h"
 
-#include <mach/iommu.h>
-
 static void msm_fb_output_poll_changed(struct drm_device *dev)
 {
        struct msm_drm_private *priv = dev->dev_private;
@@ -62,6 +60,8 @@ int msm_iommu_attach(struct drm_device *dev, struct iommu_domain *iommu,
        int i, ret;
 
        for (i = 0; i < cnt; i++) {
+               /* TODO maybe some day msm iommu won't require this hack: */
+               struct device *msm_iommu_get_ctx(const char *ctx_name);
                struct device *ctx = msm_iommu_get_ctx(names[i]);
                if (!ctx)
                        continue;
@@ -199,7 +199,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
                 * imx drm driver on iMX5
                 */
                dev_err(dev->dev, "failed to load kms\n");
-               ret = PTR_ERR(priv->kms);
+               ret = PTR_ERR(kms);
                goto fail;
        }
 
@@ -499,25 +499,41 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
                struct timespec *timeout)
 {
        struct msm_drm_private *priv = dev->dev_private;
-       unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
-       unsigned long start_jiffies = jiffies;
-       unsigned long remaining_jiffies;
        int ret;
 
-       if (time_after(start_jiffies, timeout_jiffies))
-               remaining_jiffies = 0;
-       else
-               remaining_jiffies = timeout_jiffies - start_jiffies;
-
-       ret = wait_event_interruptible_timeout(priv->fence_event,
-                       priv->completed_fence >= fence,
-                       remaining_jiffies);
-       if (ret == 0) {
-               DBG("timeout waiting for fence: %u (completed: %u)",
-                               fence, priv->completed_fence);
-               ret = -ETIMEDOUT;
-       } else if (ret != -ERESTARTSYS) {
-               ret = 0;
+       if (!priv->gpu)
+               return 0;
+
+       if (fence > priv->gpu->submitted_fence) {
+               DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
+                               fence, priv->gpu->submitted_fence);
+               return -EINVAL;
+       }
+
+       if (!timeout) {
+               /* no-wait: */
+               ret = fence_completed(dev, fence) ? 0 : -EBUSY;
+       } else {
+               unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
+               unsigned long start_jiffies = jiffies;
+               unsigned long remaining_jiffies;
+
+               if (time_after(start_jiffies, timeout_jiffies))
+                       remaining_jiffies = 0;
+               else
+                       remaining_jiffies = timeout_jiffies - start_jiffies;
+
+               ret = wait_event_interruptible_timeout(priv->fence_event,
+                               fence_completed(dev, fence),
+                               remaining_jiffies);
+
+               if (ret == 0) {
+                       DBG("timeout waiting for fence: %u (completed: %u)",
+                                       fence, priv->completed_fence);
+                       ret = -ETIMEDOUT;
+               } else if (ret != -ERESTARTSYS) {
+                       ret = 0;
+               }
        }
 
        return ret;
@@ -681,7 +697,7 @@ static struct drm_driver msm_driver = {
        .gem_vm_ops         = &vm_ops,
        .dumb_create        = msm_gem_dumb_create,
        .dumb_map_offset    = msm_gem_dumb_map_offset,
-       .dumb_destroy       = msm_gem_dumb_destroy,
+       .dumb_destroy       = drm_gem_dumb_destroy,
 #ifdef CONFIG_DEBUG_FS
        .debugfs_init       = msm_debugfs_init,
        .debugfs_cleanup    = msm_debugfs_cleanup,
index 80d75094bf0afd9bb24cb34971cd5622259717ca..df8f1d084bc1d76d1ee8dc5db948e7ebf9f87771 100644 (file)
@@ -153,7 +153,7 @@ void *msm_gem_vaddr(struct drm_gem_object *obj);
 int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
                struct work_struct *work);
 void msm_gem_move_to_active(struct drm_gem_object *obj,
-               struct msm_gpu *gpu, uint32_t fence);
+               struct msm_gpu *gpu, bool write, uint32_t fence);
 void msm_gem_move_to_inactive(struct drm_gem_object *obj);
 int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
                struct timespec *timeout);
@@ -191,6 +191,12 @@ u32 msm_readl(const void __iomem *addr);
 #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
 #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
 
+static inline bool fence_completed(struct drm_device *dev, uint32_t fence)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       return priv->completed_fence >= fence;
+}
+
 static inline int align_pitch(int width, int bpp)
 {
        int bytespp = (bpp + 7) / 8;
index 6b5a6c8c7658c5b91e905ac013779d022d299cfe..2bae46c66a30dd4c3eac623c07dbf55c70d32cb8 100644 (file)
@@ -40,9 +40,9 @@ static struct page **get_pages(struct drm_gem_object *obj)
                }
 
                msm_obj->sgt = drm_prime_pages_to_sg(p, npages);
-               if (!msm_obj->sgt) {
+               if (IS_ERR(msm_obj->sgt)) {
                        dev_err(dev->dev, "failed to allocate sgt\n");
-                       return ERR_PTR(-ENOMEM);
+                       return ERR_CAST(msm_obj->sgt);
                }
 
                msm_obj->pages = p;
@@ -159,7 +159,6 @@ out_unlock:
 out:
        switch (ret) {
        case -EAGAIN:
-               set_need_resched();
        case 0:
        case -ERESTARTSYS:
        case -EINTR:
@@ -320,13 +319,6 @@ int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
                        MSM_BO_SCANOUT | MSM_BO_WC, &args->handle);
 }
 
-int msm_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev,
-               uint32_t handle)
-{
-       /* No special work needed, drop the reference and see what falls out */
-       return drm_gem_handle_delete(file, handle);
-}
-
 int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
                uint32_t handle, uint64_t *offset)
 {
@@ -393,11 +385,14 @@ int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
 }
 
 void msm_gem_move_to_active(struct drm_gem_object *obj,
-               struct msm_gpu *gpu, uint32_t fence)
+               struct msm_gpu *gpu, bool write, uint32_t fence)
 {
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
        msm_obj->gpu = gpu;
-       msm_obj->fence = fence;
+       if (write)
+               msm_obj->write_fence = fence;
+       else
+               msm_obj->read_fence = fence;
        list_del_init(&msm_obj->mm_list);
        list_add_tail(&msm_obj->mm_list, &gpu->active_list);
 }
@@ -411,7 +406,8 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj)
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
        msm_obj->gpu = NULL;
-       msm_obj->fence = 0;
+       msm_obj->read_fence = 0;
+       msm_obj->write_fence = 0;
        list_del_init(&msm_obj->mm_list);
        list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
 
@@ -433,8 +429,18 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
        int ret = 0;
 
-       if (is_active(msm_obj) && !(op & MSM_PREP_NOSYNC))
-               ret = msm_wait_fence_interruptable(dev, msm_obj->fence, timeout);
+       if (is_active(msm_obj)) {
+               uint32_t fence = 0;
+
+               if (op & MSM_PREP_READ)
+                       fence = msm_obj->write_fence;
+               if (op & MSM_PREP_WRITE)
+                       fence = max(fence, msm_obj->read_fence);
+               if (op & MSM_PREP_NOSYNC)
+                       timeout = NULL;
+
+               ret = msm_wait_fence_interruptable(dev, fence, timeout);
+       }
 
        /* TODO cache maintenance */
 
@@ -455,9 +461,10 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
        uint64_t off = drm_vma_node_start(&obj->vma_node);
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-       seq_printf(m, "%08x: %c(%d) %2d (%2d) %08llx %p %d\n",
+       seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %d\n",
                        msm_obj->flags, is_active(msm_obj) ? 'A' : 'I',
-                       msm_obj->fence, obj->name, obj->refcount.refcount.counter,
+                       msm_obj->read_fence, msm_obj->write_fence,
+                       obj->name, obj->refcount.refcount.counter,
                        off, msm_obj->vaddr, obj->size);
 }
 
index d746f13d283c8cdaf7d885b2cd52e254a98f6061..0676f32e2c6ab917fe9980380c82137a1ad8f7ce 100644 (file)
@@ -36,7 +36,7 @@ struct msm_gem_object {
         */
        struct list_head mm_list;
        struct msm_gpu *gpu;     /* non-null if active */
-       uint32_t fence;
+       uint32_t read_fence, write_fence;
 
        /* Transiently in the process of submit ioctl, objects associated
         * with the submit are on submit->bo_list.. this only lasts for
index 3e1ef3a00f60cc929555768c1cb963b0b265e251..5281d4bc37f750e2162e4bd1f17859e4921c45cc 100644 (file)
@@ -78,7 +78,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
                }
 
                if (submit_bo.flags & BO_INVALID_FLAGS) {
-                       DBG("invalid flags: %x", submit_bo.flags);
+                       DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
                        ret = -EINVAL;
                        goto out_unlock;
                }
@@ -92,7 +92,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
                 */
                obj = idr_find(&file->object_idr, submit_bo.handle);
                if (!obj) {
-                       DBG("invalid handle %u at index %u", submit_bo.handle, i);
+                       DRM_ERROR("invalid handle %u at index %u\n", submit_bo.handle, i);
                        ret = -EINVAL;
                        goto out_unlock;
                }
@@ -100,7 +100,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
                msm_obj = to_msm_bo(obj);
 
                if (!list_empty(&msm_obj->submit_entry)) {
-                       DBG("handle %u at index %u already on submit list",
+                       DRM_ERROR("handle %u at index %u already on submit list\n",
                                        submit_bo.handle, i);
                        ret = -EINVAL;
                        goto out_unlock;
@@ -216,8 +216,9 @@ static int submit_bo(struct msm_gem_submit *submit, uint32_t idx,
                struct msm_gem_object **obj, uint32_t *iova, bool *valid)
 {
        if (idx >= submit->nr_bos) {
-               DBG("invalid buffer index: %u (out of %u)", idx, submit->nr_bos);
-               return EINVAL;
+               DRM_ERROR("invalid buffer index: %u (out of %u)\n",
+                               idx, submit->nr_bos);
+               return -EINVAL;
        }
 
        if (obj)
@@ -239,7 +240,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
        int ret;
 
        if (offset % 4) {
-               DBG("non-aligned cmdstream buffer: %u", offset);
+               DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
                return -EINVAL;
        }
 
@@ -266,7 +267,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
                        return -EFAULT;
 
                if (submit_reloc.submit_offset % 4) {
-                       DBG("non-aligned reloc offset: %u",
+                       DRM_ERROR("non-aligned reloc offset: %u\n",
                                        submit_reloc.submit_offset);
                        return -EINVAL;
                }
@@ -276,7 +277,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
 
                if ((off >= (obj->base.size / 4)) ||
                                (off < last_offset)) {
-                       DBG("invalid offset %u at reloc %u", off, i);
+                       DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
                        return -EINVAL;
                }
 
@@ -374,14 +375,15 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
                        goto out;
 
                if (submit_cmd.size % 4) {
-                       DBG("non-aligned cmdstream buffer size: %u",
+                       DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
                                        submit_cmd.size);
                        ret = -EINVAL;
                        goto out;
                }
 
-               if (submit_cmd.size >= msm_obj->base.size) {
-                       DBG("invalid cmdstream size: %u", submit_cmd.size);
+               if ((submit_cmd.size + submit_cmd.submit_offset) >=
+                               msm_obj->base.size) {
+                       DRM_ERROR("invalid cmdstream size: %u\n", submit_cmd.size);
                        ret = -EINVAL;
                        goto out;
                }
index e1e1ec9321ffe5d8db74e53a5d52b8a4122a51d9..3bab937965d1f596405864676464fe6370bf87bd 100644 (file)
 static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev)
 {
        struct drm_device *dev = gpu->dev;
-       struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
+       struct kgsl_device_platform_data *pdata;
 
        if (!pdev) {
                dev_err(dev->dev, "could not find dtv pdata\n");
                return;
        }
 
+       pdata = pdev->dev.platform_data;
        if (pdata->bus_scale_table) {
                gpu->bsc = msm_bus_scale_register_client(pdata->bus_scale_table);
                DBG("bus scale client: %08x", gpu->bsc);
@@ -230,6 +231,8 @@ static void hangcheck_timer_reset(struct msm_gpu *gpu)
 static void hangcheck_handler(unsigned long data)
 {
        struct msm_gpu *gpu = (struct msm_gpu *)data;
+       struct drm_device *dev = gpu->dev;
+       struct msm_drm_private *priv = dev->dev_private;
        uint32_t fence = gpu->funcs->last_fence(gpu);
 
        if (fence != gpu->hangcheck_fence) {
@@ -237,14 +240,22 @@ static void hangcheck_handler(unsigned long data)
                gpu->hangcheck_fence = fence;
        } else if (fence < gpu->submitted_fence) {
                /* no progress and not done.. hung! */
-               struct msm_drm_private *priv = gpu->dev->dev_private;
                gpu->hangcheck_fence = fence;
+               dev_err(dev->dev, "%s: hangcheck detected gpu lockup!\n",
+                               gpu->name);
+               dev_err(dev->dev, "%s:     completed fence: %u\n",
+                               gpu->name, fence);
+               dev_err(dev->dev, "%s:     submitted fence: %u\n",
+                               gpu->name, gpu->submitted_fence);
                queue_work(priv->wq, &gpu->recover_work);
        }
 
        /* if still more pending work, reset the hangcheck timer: */
        if (gpu->submitted_fence > gpu->hangcheck_fence)
                hangcheck_timer_reset(gpu);
+
+       /* workaround for missing irq: */
+       queue_work(priv->wq, &gpu->retire_work);
 }
 
 /*
@@ -265,7 +276,8 @@ static void retire_worker(struct work_struct *work)
                obj = list_first_entry(&gpu->active_list,
                                struct msm_gem_object, mm_list);
 
-               if (obj->fence <= fence) {
+               if ((obj->read_fence <= fence) &&
+                               (obj->write_fence <= fence)) {
                        /* move to inactive: */
                        msm_gem_move_to_inactive(&obj->base);
                        msm_gem_put_iova(&obj->base, gpu->id);
@@ -321,7 +333,11 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
                                        submit->gpu->id, &iova);
                }
 
-               msm_gem_move_to_active(&msm_obj->base, gpu, submit->fence);
+               if (submit->bos[i].flags & MSM_SUBMIT_BO_READ)
+                       msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence);
+
+               if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE)
+                       msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence);
        }
        hangcheck_timer_reset(gpu);
        mutex_unlock(&dev->struct_mutex);
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 37712a6df92358e2583b87a53df4a04cd25ba290..e290cfa4acee09bd8f0a1a2b54462e38abf0bcec 100644 (file)
@@ -113,7 +113,7 @@ nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
                pmc->use_msi = false;
                break;
        default:
-               pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", true);
+               pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", false);
                if (pmc->use_msi) {
                        pmc->use_msi = pci_enable_msi(device->pdev) == 0;
                        if (pmc->use_msi) {
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..5e891b226acf9cf60db309fc8b8c596660fe1d96 100644 (file)
@@ -707,22 +707,37 @@ 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)
-                       return ATOM_ENCODER_MODE_HDMI;
-               else if (radeon_connector->use_digital)
+               if (radeon_audio != 0) {
+                       if (radeon_connector->use_digital &&
+                           (radeon_connector->audio == RADEON_AUDIO_ENABLE))
+                               return ATOM_ENCODER_MODE_HDMI;
+                       else if (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;
+                       else
+                               return ATOM_ENCODER_MODE_CRT;
+               } else if (radeon_connector->use_digital) {
                        return ATOM_ENCODER_MODE_DVI;
-               else
+               } else {
                        return ATOM_ENCODER_MODE_CRT;
+               }
                break;
        case DRM_MODE_CONNECTOR_DVID:
        case DRM_MODE_CONNECTOR_HDMIA:
        default:
-               if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
-                   radeon_audio)
-                       return ATOM_ENCODER_MODE_HDMI;
-               else
+               if (radeon_audio != 0) {
+                       if (radeon_connector->audio == RADEON_AUDIO_ENABLE)
+                               return ATOM_ENCODER_MODE_HDMI;
+                       else if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
+                                (radeon_connector->audio == RADEON_AUDIO_AUTO))
+                               return ATOM_ENCODER_MODE_HDMI;
+                       else
+                               return ATOM_ENCODER_MODE_DVI;
+               } else {
                        return ATOM_ENCODER_MODE_DVI;
+               }
                break;
        case DRM_MODE_CONNECTOR_LVDS:
                return ATOM_ENCODER_MODE_LVDS;
@@ -730,13 +745,19 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        case DRM_MODE_CONNECTOR_DisplayPort:
                dig_connector = radeon_connector->con_priv;
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
-                   (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
+                   (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)
-                       return ATOM_ENCODER_MODE_HDMI;
-               else
+               } else if (radeon_audio != 0) {
+                       if (radeon_connector->audio == RADEON_AUDIO_ENABLE)
+                               return ATOM_ENCODER_MODE_HDMI;
+                       else if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
+                                (radeon_connector->audio == RADEON_AUDIO_AUTO))
+                               return ATOM_ENCODER_MODE_HDMI;
+                       else
+                               return ATOM_ENCODER_MODE_DVI;
+               } else {
                        return ATOM_ENCODER_MODE_DVI;
+               }
                break;
        case DRM_MODE_CONNECTOR_eDP:
                return ATOM_ENCODER_MODE_DP;
@@ -1647,8 +1668,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_RS780) && (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..9b6950d9b3c09cc193010a50bdd521939464d539 100644 (file)
@@ -1168,6 +1168,23 @@ static const struct radeon_blacklist_clocks btc_blacklist_clocks[] =
         { 25000, 30000, RADEON_SCLK_UP }
 };
 
+void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table,
+                                                    u32 *max_clock)
+{
+       u32 i, clock = 0;
+
+       if ((table == NULL) || (table->count == 0)) {
+               *max_clock = clock;
+               return;
+       }
+
+       for (i = 0; i < table->count; i++) {
+               if (clock < table->entries[i].clk)
+                       clock = table->entries[i].clk;
+       }
+       *max_clock = clock;
+}
+
 void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
                                        u32 clock, u16 max_voltage, u16 *voltage)
 {
@@ -1913,7 +1930,7 @@ static int btc_set_mc_special_registers(struct radeon_device *rdev,
                        }
                        j++;
 
-                       if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+                       if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
                                return -EINVAL;
 
                        tmp = RREG32(MC_PMG_CMD_MRS);
@@ -1928,7 +1945,7 @@ static int btc_set_mc_special_registers(struct radeon_device *rdev,
                        }
                        j++;
 
-                       if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+                       if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
                                return -EINVAL;
                        break;
                case MC_SEQ_RESERVE_M >> 2:
@@ -1942,7 +1959,7 @@ static int btc_set_mc_special_registers(struct radeon_device *rdev,
                        }
                        j++;
 
-                       if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+                       if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
                                return -EINVAL;
                        break;
                default:
@@ -2080,6 +2097,7 @@ static void btc_apply_state_adjust_rules(struct radeon_device *rdev,
        bool disable_mclk_switching;
        u32 mclk, sclk;
        u16 vddc, vddci;
+       u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
 
        if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
            btc_dpm_vblank_too_short(rdev))
@@ -2121,6 +2139,39 @@ static void btc_apply_state_adjust_rules(struct radeon_device *rdev,
                        ps->low.vddci = max_limits->vddci;
        }
 
+       /* limit clocks to max supported clocks based on voltage dependency tables */
+       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+                                                       &max_sclk_vddc);
+       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+                                                       &max_mclk_vddci);
+       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+                                                       &max_mclk_vddc);
+
+       if (max_sclk_vddc) {
+               if (ps->low.sclk > max_sclk_vddc)
+                       ps->low.sclk = max_sclk_vddc;
+               if (ps->medium.sclk > max_sclk_vddc)
+                       ps->medium.sclk = max_sclk_vddc;
+               if (ps->high.sclk > max_sclk_vddc)
+                       ps->high.sclk = max_sclk_vddc;
+       }
+       if (max_mclk_vddci) {
+               if (ps->low.mclk > max_mclk_vddci)
+                       ps->low.mclk = max_mclk_vddci;
+               if (ps->medium.mclk > max_mclk_vddci)
+                       ps->medium.mclk = max_mclk_vddci;
+               if (ps->high.mclk > max_mclk_vddci)
+                       ps->high.mclk = max_mclk_vddci;
+       }
+       if (max_mclk_vddc) {
+               if (ps->low.mclk > max_mclk_vddc)
+                       ps->low.mclk = max_mclk_vddc;
+               if (ps->medium.mclk > max_mclk_vddc)
+                       ps->medium.mclk = max_mclk_vddc;
+               if (ps->high.mclk > max_mclk_vddc)
+                       ps->high.mclk = max_mclk_vddc;
+       }
+
        /* XXX validate the min clocks required for display */
 
        if (disable_mclk_switching) {
@@ -2340,12 +2391,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 1a15e0e41950604ec8c27df9b11c6933c43d622d..3b6f12b7760ba48066f2144b73e0dc82c6521946 100644 (file)
@@ -46,6 +46,8 @@ void btc_adjust_clock_combinations(struct radeon_device *rdev,
                                   struct rv7xx_pl *pl);
 void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
                                        u32 clock, u16 max_voltage, u16 *voltage);
+void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table,
+                                                    u32 *max_clock);
 void btc_apply_voltage_delta_rules(struct radeon_device *rdev,
                                   u16 max_vddc, u16 max_vddci,
                                   u16 *vddc, u16 *vddci);
index 3cce533397c6583e345bd27cc79bd6b725926097..51e947a97edf945d02594dc0731b098ac033e1e0 100644 (file)
@@ -146,6 +146,8 @@ static const struct ci_pt_config_reg didt_config_ci[] =
 };
 
 extern u8 rv770_get_memory_module_index(struct radeon_device *rdev);
+extern void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table,
+                                                           u32 *max_clock);
 extern int ni_copy_and_switch_arb_sets(struct radeon_device *rdev,
                                       u32 arb_freq_src, u32 arb_freq_dest);
 extern u8 si_get_ddr3_mclk_frequency_ratio(u32 memory_clock);
@@ -712,6 +714,7 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev,
        struct radeon_clock_and_voltage_limits *max_limits;
        bool disable_mclk_switching;
        u32 sclk, mclk;
+       u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
        int i;
 
        if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
@@ -739,6 +742,29 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev,
                }
        }
 
+       /* limit clocks to max supported clocks based on voltage dependency tables */
+       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+                                                       &max_sclk_vddc);
+       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+                                                       &max_mclk_vddci);
+       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+                                                       &max_mclk_vddc);
+
+       for (i = 0; i < ps->performance_level_count; i++) {
+               if (max_sclk_vddc) {
+                       if (ps->performance_levels[i].sclk > max_sclk_vddc)
+                               ps->performance_levels[i].sclk = max_sclk_vddc;
+               }
+               if (max_mclk_vddci) {
+                       if (ps->performance_levels[i].mclk > max_mclk_vddci)
+                               ps->performance_levels[i].mclk = max_mclk_vddci;
+               }
+               if (max_mclk_vddc) {
+                       if (ps->performance_levels[i].mclk > max_mclk_vddc)
+                               ps->performance_levels[i].mclk = max_mclk_vddc;
+               }
+       }
+
        /* XXX validate the min clocks required for display */
 
        if (disable_mclk_switching) {
@@ -4748,12 +4774,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..9cd2bc989ac713d1604cec5ab1311ac3680066c5 100644 (file)
@@ -77,6 +77,10 @@ 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_fini_pg(struct radeon_device *rdev);
+static void cik_fini_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 +124,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[] =
@@ -1683,6 +1694,7 @@ static int cik_init_microcode(struct radeon_device *rdev)
                               fw_name);
                        release_firmware(rdev->smc_fw);
                        rdev->smc_fw = NULL;
+                       err = 0;
                } else if (rdev->smc_fw->size != smc_req_size) {
                        printk(KERN_ERR
                               "cik_smc: Bogus length %zu in firmware \"%s\"\n",
@@ -2722,7 +2734,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) ||
@@ -2835,10 +2848,8 @@ static void cik_gpu_init(struct radeon_device *rdev)
                rdev->config.cik.tile_config |= (3 << 0);
                break;
        }
-       if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT)
-               rdev->config.cik.tile_config |= 1 << 4;
-       else
-               rdev->config.cik.tile_config |= 0 << 4;
+       rdev->config.cik.tile_config |=
+               ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
        rdev->config.cik.tile_config |=
                ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
        rdev->config.cik.tile_config |=
@@ -3172,6 +3183,7 @@ int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
        r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);
        if (r) {
                DRM_ERROR("radeon: failed to get ib (%d).\n", r);
+               radeon_scratch_free(rdev, scratch);
                return r;
        }
        ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1);
@@ -3188,6 +3200,8 @@ int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
        r = radeon_fence_wait(ib.fence, false);
        if (r) {
                DRM_ERROR("radeon: fence wait failed (%d).\n", r);
+               radeon_scratch_free(rdev, scratch);
+               radeon_ib_free(rdev, &ib);
                return r;
        }
        for (i = 0; i < rdev->usec_timeout; i++) {
@@ -4013,6 +4027,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 +4040,8 @@ static int cik_cp_resume(struct radeon_device *rdev)
        if (r)
                return r;
 
+       cik_enable_gui_idle_interrupt(rdev, true);
+
        return 0;
 }
 
@@ -4173,6 +4191,10 @@ static void cik_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
        dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
                 RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
 
+       /* disable CG/PG */
+       cik_fini_pg(rdev);
+       cik_fini_cg(rdev);
+
        /* stop the rlc */
        cik_rlc_stop(rdev);
 
@@ -4442,8 +4464,8 @@ static int cik_mc_init(struct radeon_device *rdev)
        rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
        rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
        /* size in MB on si */
-       rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
-       rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+       rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL;
+       rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL;
        rdev->mc.visible_vram_size = rdev->mc.aper_size;
        si_vram_gtt_location(rdev, &rdev->mc);
        radeon_update_bandwidth_info(rdev);
@@ -4721,12 +4743,13 @@ static void cik_vm_decode_fault(struct radeon_device *rdev,
        u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT;
        u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT;
        u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT;
-       char *block = (char *)&mc_client;
+       char block[5] = { mc_client >> 24, (mc_client >> 16) & 0xff,
+               (mc_client >> 8) & 0xff, mc_client & 0xff, 0 };
 
-       printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n",
+       printk("VM fault (0x%02x, vmid %d) at page %u, %s from '%s' (0x%08x) (%d)\n",
               protections, vmid, addr,
               (status & MEMORY_CLIENT_RW_MASK) ? "write" : "read",
-              block, mc_id);
+              block, mc_client, mc_id);
 }
 
 /**
@@ -5376,7 +5399,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 +5410,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 +5567,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 +5831,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 +5845,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 +5921,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 +6064,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 +6085,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..9fcd338c0fcf6bb1e113c80c8b116bcf5c56abbc 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)
@@ -105,6 +113,9 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)
        u8 *sadb;
        int sad_count;
 
+       /* XXX: setting this register causes hangs on some asics */
+       return;
+
        if (!dig->afmt->pin)
                return;
 
index 555164e270a79347fb36b9cadab09d90754c4306..b5c67a99dda9b34707c3ba7eb20a682f9c7fe089 100644 (file)
@@ -3131,7 +3131,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
                rdev->config.evergreen.sx_max_export_size = 256;
                rdev->config.evergreen.sx_max_export_pos_size = 64;
                rdev->config.evergreen.sx_max_export_smx_size = 192;
-               rdev->config.evergreen.max_hw_contexts = 8;
+               rdev->config.evergreen.max_hw_contexts = 4;
                rdev->config.evergreen.sq_num_cf_insts = 2;
 
                rdev->config.evergreen.sc_prim_fifo_size = 0x40;
index f71ce390aebe581dd08998ce29d98e4b1058155c..fe1de855775ecca1491ced31f797f5cac6d05abc 100644 (file)
@@ -67,6 +67,9 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)
        u8 *sadb;
        int sad_count;
 
+       /* XXX: setting this register causes hangs on some asics */
+       return;
+
        list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
                if (connector->encoder == encoder)
                        radeon_connector = to_radeon_connector(connector);
@@ -288,8 +291,7 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
        /* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */
 
        WREG32(HDMI_ACR_PACKET_CONTROL + offset,
-              HDMI_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */
-              HDMI_ACR_SOURCE); /* select SW CTS value */
+              HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
 
        evergreen_hdmi_update_ACR(encoder, mode->clock);
 
index 8768fd6a1e2707acf1006f9afff44eb1a173fd4b..4f6d2962767dced17ae7f5f3e44e79bce4f51bbf 100644 (file)
  * 6. COMMAND [29:22] | BYTE_COUNT [20:0]
  */
 #              define PACKET3_CP_DMA_DST_SEL(x)    ((x) << 20)
-                /* 0 - SRC_ADDR
+                /* 0 - DST_ADDR
                 * 1 - GDS
                 */
 #              define PACKET3_CP_DMA_ENGINE(x)     ((x) << 27)
 #              define PACKET3_CP_DMA_CP_SYNC       (1 << 31)
 /* COMMAND */
 #              define PACKET3_CP_DMA_DIS_WC        (1 << 21)
-#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 23)
+#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 22)
                 /* 0 - none
                 * 1 - 8 in 16
                 * 2 - 8 in 32
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 93c1f9ef5da9b5ee7c3474bfaaae5bbe7497cf91..cac2866d79da441dfbbbcef860f713c9c7ad5a58 100644 (file)
@@ -804,6 +804,7 @@ int ni_init_microcode(struct radeon_device *rdev)
                               fw_name);
                        release_firmware(rdev->smc_fw);
                        rdev->smc_fw = NULL;
+                       err = 0;
                } else if (rdev->smc_fw->size != smc_req_size) {
                        printk(KERN_ERR
                               "ni_mc: Bogus length %zu in firmware \"%s\"\n",
index f7b625c9e0e9cfa355ad27b0f1f2952bc9de8427..f26339028154274609f31247580d03cbbed0d312 100644 (file)
@@ -787,6 +787,7 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev,
        bool disable_mclk_switching;
        u32 mclk, sclk;
        u16 vddc, vddci;
+       u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
        int i;
 
        if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
@@ -813,6 +814,29 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev,
                }
        }
 
+       /* limit clocks to max supported clocks based on voltage dependency tables */
+       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+                                                       &max_sclk_vddc);
+       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+                                                       &max_mclk_vddci);
+       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+                                                       &max_mclk_vddc);
+
+       for (i = 0; i < ps->performance_level_count; i++) {
+               if (max_sclk_vddc) {
+                       if (ps->performance_levels[i].sclk > max_sclk_vddc)
+                               ps->performance_levels[i].sclk = max_sclk_vddc;
+               }
+               if (max_mclk_vddci) {
+                       if (ps->performance_levels[i].mclk > max_mclk_vddci)
+                               ps->performance_levels[i].mclk = max_mclk_vddci;
+               }
+               if (max_mclk_vddc) {
+                       if (ps->performance_levels[i].mclk > max_mclk_vddc)
+                               ps->performance_levels[i].mclk = max_mclk_vddc;
+               }
+       }
+
        /* XXX validate the min clocks required for display */
 
        if (disable_mclk_switching) {
@@ -3865,12 +3889,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..d71333033b2ba0bc63f9e710a23f710d7b96b066 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)
@@ -2926,9 +2933,11 @@ static int r100_debugfs_cp_ring_info(struct seq_file *m, void *data)
        seq_printf(m, "CP_RB_RPTR 0x%08x\n", rdp);
        seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw);
        seq_printf(m, "%u dwords in ring\n", count);
-       for (j = 0; j <= count; j++) {
-               i = (rdp + j) & ring->ptr_mask;
-               seq_printf(m, "r[%04d]=0x%08x\n", i, ring->ring[i]);
+       if (ring->ready) {
+               for (j = 0; j <= count; j++) {
+                       i = (rdp + j) & ring->ptr_mask;
+                       seq_printf(m, "r[%04d]=0x%08x\n", i, ring->ring[i]);
+               }
        }
        return 0;
 }
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..f9be22062df1eb8048384cabec6219e8a5238fff 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);
 }
 
 /*
@@ -2283,6 +2302,7 @@ int r600_init_microcode(struct radeon_device *rdev)
                               fw_name);
                        release_firmware(rdev->smc_fw);
                        rdev->smc_fw = NULL;
+                       err = 0;
                } else if (rdev->smc_fw->size != smc_req_size) {
                        printk(KERN_ERR
                               "smc: Bogus length %zu in firmware \"%s\"\n",
index fa0de46fcc0d1cc5d714f6c8c6cc8e0a958d8001..5513d8f06252e13e11e27e9d21d5aecae775b5a8 100644 (file)
@@ -1084,7 +1084,7 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
                                rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].dclk =
                                        le16_to_cpu(uvd_clk->usDClkLow) | (uvd_clk->ucDClkHigh << 16);
                                rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].v =
-                                       le16_to_cpu(limits->entries[i].usVoltage);
+                                       le16_to_cpu(entry->usVoltage);
                                entry = (ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *)
                                        ((u8 *)entry + sizeof(ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record));
                        }
@@ -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 f443010ce90b1ed7607565474b2ba0851e378789..06022e3b9c3bdc0a0660a60c448e25038659e41d 100644 (file)
@@ -57,15 +57,15 @@ enum r600_hdmi_iec_status_bits {
 static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {
     /*      32kHz        44.1kHz       48kHz    */
     /* Clock      N     CTS      N     CTS      N     CTS */
-    {  25174,  4576,  28125,  7007,  31250,  6864,  28125 }, /*  25,20/1.001 MHz */
+    {  25175,  4576,  28125,  7007,  31250,  6864,  28125 }, /*  25,20/1.001 MHz */
     {  25200,  4096,  25200,  6272,  28000,  6144,  25200 }, /*  25.20       MHz */
     {  27000,  4096,  27000,  6272,  30000,  6144,  27000 }, /*  27.00       MHz */
     {  27027,  4096,  27027,  6272,  30030,  6144,  27027 }, /*  27.00*1.001 MHz */
     {  54000,  4096,  54000,  6272,  60000,  6144,  54000 }, /*  54.00       MHz */
     {  54054,  4096,  54054,  6272,  60060,  6144,  54054 }, /*  54.00*1.001 MHz */
-    {  74175, 11648, 210937, 17836, 234375, 11648, 140625 }, /*  74.25/1.001 MHz */
+    {  74176, 11648, 210937, 17836, 234375, 11648, 140625 }, /*  74.25/1.001 MHz */
     {  74250,  4096,  74250,  6272,  82500,  6144,  74250 }, /*  74.25       MHz */
-    { 148351, 11648, 421875,  8918, 234375,  5824, 140625 }, /* 148.50/1.001 MHz */
+    { 148352, 11648, 421875,  8918, 234375,  5824, 140625 }, /* 148.50/1.001 MHz */
     { 148500,  4096, 148500,  6272, 165000,  6144, 148500 }, /* 148.50       MHz */
     {      0,  4096,      0,  6272,      0,  6144,      0 }  /* Other */
 };
@@ -75,8 +75,15 @@ static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {
  */
 static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int N, int freq)
 {
-       if (*CTS == 0)
-               *CTS = clock * N / (128 * freq) * 1000;
+       u64 n;
+       u32 d;
+
+       if (*CTS == 0) {
+               n = (u64)clock * (u64)N * 1000ULL;
+               d = 128 * freq;
+               do_div(n, d);
+               *CTS = n;
+       }
        DRM_DEBUG("Using ACR timing N=%d CTS=%d for frequency %d\n",
                  N, *CTS, freq);
 }
@@ -257,10 +264,7 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
         * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
         * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
         */
-       if (ASIC_IS_DCE3(rdev)) {
-               /* according to the reg specs, this should DCE3.2 only, but in
-                * practice it seems to cover DCE3.0 as well.
-                */
+       if (ASIC_IS_DCE32(rdev)) {
                if (dig->dig_encoder == 0) {
                        dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
                        dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
@@ -276,8 +280,21 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
                        WREG32(DCCG_AUDIO_DTO1_MODULE, dto_modulo);
                        WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
                }
+       } else if (ASIC_IS_DCE3(rdev)) {
+               /* according to the reg specs, this should DCE3.2 only, but in
+                * practice it seems to cover DCE3.0/3.1 as well.
+                */
+               if (dig->dig_encoder == 0) {
+                       WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
+                       WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
+                       WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
+               } else {
+                       WREG32(DCCG_AUDIO_DTO1_PHASE, base_rate * 100);
+                       WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100);
+                       WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
+               }
        } else {
-               /* according to the reg specs, this should be DCE2.0 and DCE3.0 */
+               /* according to the reg specs, this should be DCE2.0 and DCE3.0/3.1 */
                WREG32(AUDIO_DTO, AUDIO_DTO_PHASE(base_rate / 10) |
                       AUDIO_DTO_MODULE(clock / 10));
        }
@@ -292,6 +309,9 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
        u8 *sadb;
        int sad_count;
 
+       /* XXX: setting this register causes hangs on some asics */
+       return;
+
        list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
                if (connector->encoder == encoder)
                        radeon_connector = to_radeon_connector(connector);
@@ -434,8 +454,8 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
        }
 
        WREG32(HDMI0_ACR_PACKET_CONTROL + offset,
-              HDMI0_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */
-              HDMI0_ACR_SOURCE); /* select SW CTS value */
+              HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
+              HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
 
        WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
               HDMI0_NULL_SEND | /* send null packets when required */
index 454f90a849e47d6ef6e6b87c0bf6c97d3a31b54f..7b3c7b5932c5a289be3fd58d05b7392791c6a4ff 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)
  */
 #              define PACKET3_CP_DMA_CP_SYNC       (1 << 31)
 /* COMMAND */
-#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 23)
+#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 22)
                 /* 0 - none
                 * 1 - 8 in 16
                 * 2 - 8 in 32
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..8f7e04538fd624a5ecb1c302e8b9d5f2455f808a 100644 (file)
@@ -1004,6 +1004,8 @@ static struct radeon_asic rv6xx_asic = {
                .wait_for_vblank = &avivo_wait_for_vblank,
                .set_backlight_level = &atombios_set_backlight_level,
                .get_backlight_level = &atombios_get_backlight_level,
+               .hdmi_enable = &r600_hdmi_enable,
+               .hdmi_setmode = &r600_hdmi_setmode,
        },
        .copy = {
                .blit = &r600_copy_cpdma,
@@ -1037,6 +1039,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 +1129,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 +1145,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 +1796,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 +2172,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 +2397,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 +2486,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 +2514,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 404e25d285ba816b1f34308ce79537b8a0d44a90..f79ee184ffd5849f4d0e0ec1b87b0d94d0f1f131 100644 (file)
@@ -1367,6 +1367,7 @@ bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
        int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info);
        uint16_t data_offset, size;
        struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info;
+       struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT *ss_assign;
        uint8_t frev, crev;
        int i, num_indices;
 
@@ -1378,18 +1379,21 @@ bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
 
                num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
                        sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
-
+               ss_assign = (struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT*)
+                       ((u8 *)&ss_info->asSS_Info[0]);
                for (i = 0; i < num_indices; i++) {
-                       if (ss_info->asSS_Info[i].ucSS_Id == id) {
+                       if (ss_assign->ucSS_Id == id) {
                                ss->percentage =
-                                       le16_to_cpu(ss_info->asSS_Info[i].usSpreadSpectrumPercentage);
-                               ss->type = ss_info->asSS_Info[i].ucSpreadSpectrumType;
-                               ss->step = ss_info->asSS_Info[i].ucSS_Step;
-                               ss->delay = ss_info->asSS_Info[i].ucSS_Delay;
-                               ss->range = ss_info->asSS_Info[i].ucSS_Range;
-                               ss->refdiv = ss_info->asSS_Info[i].ucRecommendedRef_Div;
+                                       le16_to_cpu(ss_assign->usSpreadSpectrumPercentage);
+                               ss->type = ss_assign->ucSpreadSpectrumType;
+                               ss->step = ss_assign->ucSS_Step;
+                               ss->delay = ss_assign->ucSS_Delay;
+                               ss->range = ss_assign->ucSS_Range;
+                               ss->refdiv = ss_assign->ucRecommendedRef_Div;
                                return true;
                        }
+                       ss_assign = (struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT*)
+                               ((u8 *)ss_assign + sizeof(struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT));
                }
        }
        return false;
@@ -1477,6 +1481,12 @@ union asic_ss_info {
        struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3;
 };
 
+union asic_ss_assignment {
+       struct _ATOM_ASIC_SS_ASSIGNMENT v1;
+       struct _ATOM_ASIC_SS_ASSIGNMENT_V2 v2;
+       struct _ATOM_ASIC_SS_ASSIGNMENT_V3 v3;
+};
+
 bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                                      struct radeon_atom_ss *ss,
                                      int id, u32 clock)
@@ -1485,6 +1495,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
        int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
        uint16_t data_offset, size;
        union asic_ss_info *ss_info;
+       union asic_ss_assignment *ss_assign;
        uint8_t frev, crev;
        int i, num_indices;
 
@@ -1509,45 +1520,52 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                        num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
                                sizeof(ATOM_ASIC_SS_ASSIGNMENT);
 
+                       ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info.asSpreadSpectrum[0]);
                        for (i = 0; i < num_indices; i++) {
-                               if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) &&
-                                   (clock <= le32_to_cpu(ss_info->info.asSpreadSpectrum[i].ulTargetClockRange))) {
+                               if ((ss_assign->v1.ucClockIndication == id) &&
+                                   (clock <= le32_to_cpu(ss_assign->v1.ulTargetClockRange))) {
                                        ss->percentage =
-                                               le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
-                                       ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode;
-                                       ss->rate = le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz);
+                                               le16_to_cpu(ss_assign->v1.usSpreadSpectrumPercentage);
+                                       ss->type = ss_assign->v1.ucSpreadSpectrumMode;
+                                       ss->rate = le16_to_cpu(ss_assign->v1.usSpreadRateInKhz);
                                        return true;
                                }
+                               ss_assign = (union asic_ss_assignment *)
+                                       ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT));
                        }
                        break;
                case 2:
                        num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
                                sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
+                       ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_2.asSpreadSpectrum[0]);
                        for (i = 0; i < num_indices; i++) {
-                               if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) &&
-                                   (clock <= le32_to_cpu(ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange))) {
+                               if ((ss_assign->v2.ucClockIndication == id) &&
+                                   (clock <= le32_to_cpu(ss_assign->v2.ulTargetClockRange))) {
                                        ss->percentage =
-                                               le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
-                                       ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode;
-                                       ss->rate = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+                                               le16_to_cpu(ss_assign->v2.usSpreadSpectrumPercentage);
+                                       ss->type = ss_assign->v2.ucSpreadSpectrumMode;
+                                       ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz);
                                        if ((crev == 2) &&
                                            ((id == ASIC_INTERNAL_ENGINE_SS) ||
                                             (id == ASIC_INTERNAL_MEMORY_SS)))
                                                ss->rate /= 100;
                                        return true;
                                }
+                               ss_assign = (union asic_ss_assignment *)
+                                       ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2));
                        }
                        break;
                case 3:
                        num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
                                sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
+                       ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_3.asSpreadSpectrum[0]);
                        for (i = 0; i < num_indices; i++) {
-                               if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) &&
-                                   (clock <= le32_to_cpu(ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange))) {
+                               if ((ss_assign->v3.ucClockIndication == id) &&
+                                   (clock <= le32_to_cpu(ss_assign->v3.ulTargetClockRange))) {
                                        ss->percentage =
-                                               le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
-                                       ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
-                                       ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+                                               le16_to_cpu(ss_assign->v3.usSpreadSpectrumPercentage);
+                                       ss->type = ss_assign->v3.ucSpreadSpectrumMode;
+                                       ss->rate = le16_to_cpu(ss_assign->v3.usSpreadRateIn10Hz);
                                        if ((id == ASIC_INTERNAL_ENGINE_SS) ||
                                            (id == ASIC_INTERNAL_MEMORY_SS))
                                                ss->rate /= 100;
@@ -1555,6 +1573,8 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                                                radeon_atombios_get_igp_ss_overrides(rdev, ss, id);
                                        return true;
                                }
+                               ss_assign = (union asic_ss_assignment *)
+                                       ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3));
                        }
                        break;
                default:
index 2399f25ec0370cfba03b256174de69e407e01353..64565732cb98cf25af4e4d1f564e307c85cf4a8f 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,12 @@ radeon_add_atom_connector(struct drm_device *dev,
                        drm_object_attach_property(&radeon_connector->base.base,
                                                      rdev->mode_info.underscan_vborder_property,
                                                      0);
+                       if (radeon_audio != 0)
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.audio_property,
+                                                          (radeon_audio == 1) ?
+                                                          RADEON_AUDIO_AUTO :
+                                                          RADEON_AUDIO_DISABLE);
                        subpixel_order = SubPixelHorizontalRGB;
                        connector->interlace_allowed = true;
                        if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
@@ -1634,6 +1679,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 +1757,13 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.underscan_vborder_property,
                                                              0);
                        }
+                       if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.audio_property,
+                                                          (radeon_audio == 1) ?
+                                                          RADEON_AUDIO_AUTO :
+                                                          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 +1804,13 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.underscan_vborder_property,
                                                              0);
                        }
+                       if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.audio_property,
+                                                          (radeon_audio == 1) ?
+                                                          RADEON_AUDIO_AUTO :
+                                                          RADEON_AUDIO_DISABLE);
+                       }
                        subpixel_order = SubPixelHorizontalRGB;
                        connector->interlace_allowed = true;
                        if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
@@ -1787,6 +1850,13 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.underscan_vborder_property,
                                                              0);
                        }
+                       if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.audio_property,
+                                                          (radeon_audio == 1) ?
+                                                          RADEON_AUDIO_AUTO :
+                                                          RADEON_AUDIO_DISABLE);
+                       }
                        connector->interlace_allowed = true;
                        /* in theory with a DP to VGA converter... */
                        connector->doublescan_allowed = false;
@@ -1797,7 +1867,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..80285e35bc6513fda3d5f5c975399a60feaab1e3 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 || drm_pci_device_is_agp(p->rdev->ddev))) {
                        /* 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..841d0e09be3e9fb109b5afd45d012590a0ee6433 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);
@@ -1309,13 +1320,22 @@ int radeon_device_init(struct radeon_device *rdev,
                        return r;
        }
        if ((radeon_testing & 1)) {
-               radeon_test_moves(rdev);
+               if (rdev->accel_working)
+                       radeon_test_moves(rdev);
+               else
+                       DRM_INFO("radeon: acceleration disabled, skipping move tests\n");
        }
        if ((radeon_testing & 2)) {
-               radeon_test_syncing(rdev);
+               if (rdev->accel_working)
+                       radeon_test_syncing(rdev);
+               else
+                       DRM_INFO("radeon: acceleration disabled, skipping sync tests\n");
        }
        if (radeon_benchmarking) {
-               radeon_benchmark(rdev, radeon_benchmarking);
+               if (rdev->accel_working)
+                       radeon_benchmark(rdev, radeon_benchmarking);
+               else
+                       DRM_INFO("radeon: acceleration disabled, skipping benchmarks\n");
        }
        return 0;
 }
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..9c14a1ba1de43aa9086741fda75c9aba3cc96394 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;
@@ -196,7 +196,7 @@ module_param_named(connector_table, radeon_connector_table, int, 0444);
 MODULE_PARM_DESC(tv, "TV enable (0 = disable)");
 module_param_named(tv, radeon_tv, int, 0444);
 
-MODULE_PARM_DESC(audio, "Audio enable (1 = enable)");
+MODULE_PARM_DESC(audio, "Audio enable (-1 = auto, 0 = disable, 1 = enable)");
 module_param_named(audio, radeon_audio, int, 0444);
 
 MODULE_PARM_DESC(disp_priority, "Display Priority (0 = auto, 1 = normal, 2 = high)");
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..4f6b7fc7ad3cad3a90017c6d7f75192c4c55452a 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:
@@ -895,6 +945,8 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)
                if (enable) {
                        mutex_lock(&rdev->pm.mutex);
                        rdev->pm.dpm.uvd_active = true;
+                       /* disable this for now */
+#if 0
                        if ((rdev->pm.dpm.sd == 1) && (rdev->pm.dpm.hd == 0))
                                dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_SD;
                        else if ((rdev->pm.dpm.sd == 2) && (rdev->pm.dpm.hd == 0))
@@ -904,6 +956,7 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)
                        else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 2))
                                dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD2;
                        else
+#endif
                                dpm_state = POWER_STATE_TYPE_INTERNAL_UVD;
                        rdev->pm.dpm.state = dpm_state;
                        mutex_unlock(&rdev->pm.mutex);
@@ -952,7 +1005,7 @@ static void radeon_pm_resume_old(struct radeon_device *rdev)
 {
        /* set up the default clocks if the MC ucode is loaded */
        if ((rdev->family >= CHIP_BARTS) &&
-           (rdev->family <= CHIP_HAINAN) &&
+           (rdev->family <= CHIP_CAYMAN) &&
            rdev->mc_fw) {
                if (rdev->pm.default_vddc)
                        radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
@@ -996,7 +1049,7 @@ static void radeon_pm_resume_dpm(struct radeon_device *rdev)
        if (ret) {
                DRM_ERROR("radeon: dpm resume failed\n");
                if ((rdev->family >= CHIP_BARTS) &&
-                   (rdev->family <= CHIP_HAINAN) &&
+                   (rdev->family <= CHIP_CAYMAN) &&
                    rdev->mc_fw) {
                        if (rdev->pm.default_vddc)
                                radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
@@ -1047,7 +1100,7 @@ static int radeon_pm_init_old(struct radeon_device *rdev)
                radeon_pm_init_profile(rdev);
                /* set up the default clocks if the MC ucode is loaded */
                if ((rdev->family >= CHIP_BARTS) &&
-                   (rdev->family <= CHIP_HAINAN) &&
+                   (rdev->family <= CHIP_CAYMAN) &&
                    rdev->mc_fw) {
                        if (rdev->pm.default_vddc)
                                radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
@@ -1102,9 +1155,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;
@@ -1132,7 +1186,7 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev)
        if (ret) {
                rdev->pm.dpm_enabled = false;
                if ((rdev->family >= CHIP_BARTS) &&
-                   (rdev->family <= CHIP_HAINAN) &&
+                   (rdev->family <= CHIP_CAYMAN) &&
                    rdev->mc_fw) {
                        if (rdev->pm.default_vddc)
                                radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
index 46a25f037b843b70ebfb04e77ad55901111efd02..18254e1c3e718ee1c7c4cdd4321bf95b15581970 100644 (file)
@@ -839,9 +839,11 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
         * packet that is the root issue
         */
        i = (ring->rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask;
-       for (j = 0; j <= (count + 32); j++) {
-               seq_printf(m, "r[%5d]=0x%08x\n", i, ring->ring[i]);
-               i = (i + 1) & ring->ptr_mask;
+       if (ring->ready) {
+               for (j = 0; j <= (count + 32); j++) {
+                       seq_printf(m, "r[%5d]=0x%08x\n", i, ring->ring[i]);
+                       i = (i + 1) & ring->ptr_mask;
+               }
        }
        return 0;
 }
index f4d6bcee9006451ca377b94ece370806a8f89d2d..12e8099a0823e23a1218c1e5a3f07e78bbfbfcd0 100644 (file)
@@ -36,8 +36,8 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
        struct radeon_bo *vram_obj = NULL;
        struct radeon_bo **gtt_obj = NULL;
        uint64_t gtt_addr, vram_addr;
-       unsigned i, n, size;
-       int r, ring;
+       unsigned n, size;
+       int i, r, ring;
 
        switch (flag) {
        case RADEON_TEST_COPY_DMA:
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 1a01bbff9bfa4f5c9ca1d354cd99abae981a36ce..308eff5be1b420b74b18ccb1b1e0c89f4bd67f32 100644 (file)
@@ -799,7 +799,8 @@ void radeon_uvd_note_usage(struct radeon_device *rdev)
                    (rdev->pm.dpm.hd != hd)) {
                        rdev->pm.dpm.sd = sd;
                        rdev->pm.dpm.hd = hd;
-                       streams_changed = true;
+                       /* disable this for now */
+                       /*streams_changed = true;*/
                }
        }
 
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..d96f7cbca0a115f58eaeca9df3a6e585d6b3445d 100644 (file)
@@ -83,6 +83,11 @@ 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 void si_fini_pg(struct radeon_device *rdev);
+static void si_fini_cg(struct radeon_device *rdev);
+static void si_rlc_stop(struct radeon_device *rdev);
 
 static const u32 verde_rlc_save_restore_register_list[] =
 {
@@ -1676,6 +1681,7 @@ static int si_init_microcode(struct radeon_device *rdev)
                       fw_name);
                release_firmware(rdev->smc_fw);
                rdev->smc_fw = NULL;
+               err = 0;
        } else if (rdev->smc_fw->size != smc_req_size) {
                printk(KERN_ERR
                       "si_smc: Bogus length %zu in firmware \"%s\"\n",
@@ -3386,6 +3392,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 +3509,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;
 }
 
@@ -3602,6 +3612,13 @@ static void si_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
        dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
                 RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
 
+       /* disable PG/CG */
+       si_fini_pg(rdev);
+       si_fini_cg(rdev);
+
+       /* stop the rlc */
+       si_rlc_stop(rdev);
+
        /* Disable CP parsing/prefetching */
        WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
 
@@ -4888,7 +4905,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 +5267,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 +5276,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 +5427,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 +5579,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 +5706,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 +5727,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..2332aa1bf93c7c40936710c7e8595c6d49f6514b 100644 (file)
@@ -2910,6 +2910,7 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
        bool disable_sclk_switching = false;
        u32 mclk, sclk;
        u16 vddc, vddci;
+       u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
        int i;
 
        if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
@@ -2943,6 +2944,29 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
                }
        }
 
+       /* limit clocks to max supported clocks based on voltage dependency tables */
+       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+                                                       &max_sclk_vddc);
+       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+                                                       &max_mclk_vddci);
+       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+                                                       &max_mclk_vddc);
+
+       for (i = 0; i < ps->performance_level_count; i++) {
+               if (max_sclk_vddc) {
+                       if (ps->performance_levels[i].sclk > max_sclk_vddc)
+                               ps->performance_levels[i].sclk = max_sclk_vddc;
+               }
+               if (max_mclk_vddci) {
+                       if (ps->performance_levels[i].mclk > max_mclk_vddci)
+                               ps->performance_levels[i].mclk = max_mclk_vddci;
+               }
+               if (max_mclk_vddc) {
+                       if (ps->performance_levels[i].mclk > max_mclk_vddc)
+                               ps->performance_levels[i].mclk = max_mclk_vddc;
+               }
+       }
+
        /* XXX validate the min clocks required for display */
 
        if (disable_mclk_switching) {
@@ -5184,7 +5208,7 @@ static int si_set_mc_special_registers(struct radeon_device *rdev,
                                        table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
                        }
                        j++;
-                       if (j > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+                       if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
                                return -EINVAL;
 
                        if (!pi->mem_gddr5) {
@@ -5194,7 +5218,7 @@ static int si_set_mc_special_registers(struct radeon_device *rdev,
                                        table->mc_reg_table_entry[k].mc_data[j] =
                                                (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
                                j++;
-                               if (j > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+                               if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
                                        return -EINVAL;
                        }
                        break;
@@ -5207,7 +5231,7 @@ static int si_set_mc_special_registers(struct radeon_device *rdev,
                                        (temp_reg & 0xffff0000) |
                                        (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
                        j++;
-                       if (j > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+                       if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
                                return -EINVAL;
                        break;
                default:
@@ -6075,12 +6099,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 52d2ab6b67a0b8876bdfa1710756f582b3927382..7e2e0ea66a008f491f5396bada706ca469b23f0b 100644 (file)
  * 6. COMMAND [30:21] | BYTE_COUNT [20:0]
  */
 #              define PACKET3_CP_DMA_DST_SEL(x)    ((x) << 20)
-                /* 0 - SRC_ADDR
+                /* 0 - DST_ADDR
                 * 1 - GDS
                 */
 #              define PACKET3_CP_DMA_ENGINE(x)     ((x) << 27)
 #              define PACKET3_CP_DMA_CP_SYNC       (1 << 31)
 /* COMMAND */
 #              define PACKET3_CP_DMA_DIS_WC        (1 << 21)
-#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 23)
+#              define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 22)
                 /* 0 - none
                 * 1 - 8 in 16
                 * 2 - 8 in 32
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..9364129ba292e1b5412a0d10818ed158c95bb0fa 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 = false;
        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 1a90f0a2f7e5aa7b994558b18a3cffd2d1254ee8..0508f93b9795fbc2b4ccf9c8f34ea62383a7e138 100644 (file)
@@ -740,9 +740,17 @@ static void vmw_postclose(struct drm_device *dev,
        struct vmw_fpriv *vmw_fp;
 
        vmw_fp = vmw_fpriv(file_priv);
-       ttm_object_file_release(&vmw_fp->tfile);
-       if (vmw_fp->locked_master)
+
+       if (vmw_fp->locked_master) {
+               struct vmw_master *vmaster =
+                       vmw_master(vmw_fp->locked_master);
+
+               ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
+               ttm_vt_unlock(&vmaster->lock);
                drm_master_put(&vmw_fp->locked_master);
+       }
+
+       ttm_object_file_release(&vmw_fp->tfile);
        kfree(vmw_fp);
 }
 
@@ -925,14 +933,13 @@ static void vmw_master_drop(struct drm_device *dev,
 
        vmw_fp->locked_master = drm_master_get(file_priv->master);
        ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile);
-       vmw_execbuf_release_pinned_bo(dev_priv);
-
        if (unlikely((ret != 0))) {
                DRM_ERROR("Unable to lock TTM at VT switch.\n");
                drm_master_put(&vmw_fp->locked_master);
        }
 
-       ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
+       ttm_lock_set_kill(&vmaster->lock, false, SIGTERM);
+       vmw_execbuf_release_pinned_bo(dev_priv);
 
        if (!dev_priv->enable_fb) {
                ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM);
index 0e67cf41065d801e6526d23dc5cdf375bdabe1c7..37fb4befec82634ccf3a504428af8ed60f4a0e56 100644 (file)
@@ -970,7 +970,7 @@ void vmw_resource_unreserve(struct vmw_resource *res,
        if (new_backup)
                res->backup_offset = new_backup_offset;
 
-       if (!res->func->may_evict)
+       if (!res->func->may_evict || res->id == -1)
                return;
 
        write_lock(&dev_priv->resource_lock);
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..c91d547191dd2b7a511b1564523c8f649ec6ac2d 100644 (file)
@@ -241,6 +241,7 @@ config HID_HOLTEK
          - Sharkoon Drakonia / Perixx MX-2000 gaming mice
          - Tracer Sniper TRM-503 / NOVA Gaming Slider X200 /
            Zalman ZM-GM1
+         - SHARKOON DarkGlider Gaming mouse
 
 config HOLTEK_FF
        bool "Holtek On Line Grip force feedback support"
@@ -773,7 +774,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..e80da62363bc2c96d6be419f89d002f3a55e4d36 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;
@@ -321,7 +319,7 @@ static s32 item_sdata(struct hid_item *item)
 
 static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
 {
-       __u32 raw_value;
+       __s32 raw_value;
        switch (item->tag) {
        case HID_GLOBAL_ITEM_TAG_PUSH:
 
@@ -372,10 +370,11 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
                return 0;
 
        case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
-               /* Units exponent negative numbers are given through a
-                * two's complement.
-                * See "6.2.2.7 Global Items" for more information. */
-               raw_value = item_udata(item);
+               /* Many devices provide unit exponent as a two's complement
+                * nibble due to the common misunderstanding of HID
+                * specification 1.11, 6.2.2.7 Global Items. Attempt to handle
+                * both this and the standard encoding. */
+               raw_value = item_sdata(item);
                if (!(raw_value & 0xfffffff0))
                        parser->global.unit_exponent = hid_snto32(raw_value, 4);
                else
@@ -801,6 +800,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 +1353,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;
@@ -1659,6 +1716,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
        { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
@@ -1813,6 +1871,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO2, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
        { }
 };
index 7e6db3cf46f9eb39746fcc4ac4b4e29296caa569..e696566cde46420334d1f416b53c2675ec581a7b 100644 (file)
@@ -27,6 +27,7 @@
  * - USB ID 04d9:a067, sold as Sharkoon Drakonia and Perixx MX-2000
  * - USB ID 04d9:a04a, sold as Tracer Sniper TRM-503, NOVA Gaming Slider X200
  *   and Zalman ZM-GM1
+ * - USB ID 04d9:a081, sold as SHARKOON DarkGlider Gaming mouse
  */
 
 static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
@@ -46,6 +47,7 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                        }
                        break;
                case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A:
+               case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081:
                        if (*rsize >= 113 && rdesc[106] == 0xff && rdesc[107] == 0x7f
                                        && rdesc[111] == 0xff && rdesc[112] == 0x7f) {
                                hid_info(hdev, "Fixing up report descriptor\n");
@@ -63,6 +65,8 @@ static const struct hid_device_id holtek_mouse_devices[] = {
                        USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
                        USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
+                       USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, holtek_mouse_devices);
index e60e8d530697fcaf0a7c4a43f42e53b455de6f4d..f0296a50be5f754fc7be2b8f593bf2b2beca1e22 100644 (file)
 #define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD      0xa055
 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067    0xa067
 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A    0xa04a
+#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081    0xa081
 
 #define USB_VENDOR_ID_IMATION          0x0718
 #define USB_DEVICE_ID_DISC_STAKKA      0xd000
 #define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN   0x0003
 
 #define USB_VENDOR_ID_NINTENDO         0x057e
+#define USB_VENDOR_ID_NINTENDO2                0x054c
 #define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306
 #define USB_DEVICE_ID_NINTENDO_WIIMOTE2        0x0330
 
 #define USB_DEVICE_ID_SYNAPTICS_COMP_TP        0x0009
 #define USB_DEVICE_ID_SYNAPTICS_WTP    0x0010
 #define USB_DEVICE_ID_SYNAPTICS_DPAD   0x0013
+#define USB_DEVICE_ID_SYNAPTICS_LTS1   0x0af8
+#define USB_DEVICE_ID_SYNAPTICS_LTS2   0x1d10
 
 #define USB_VENDOR_ID_THINGM           0x27b8
 #define USB_DEVICE_ID_BLINK1           0x01ed
 #define USB_VENDOR_ID_PRIMAX   0x0461
 #define USB_DEVICE_ID_PRIMAX_KEYBOARD  0x4e05
 
+#define USB_VENDOR_ID_SIS      0x0457
+#define USB_DEVICE_ID_SIS_TS   0x1013
+
 #endif
index b420f4a0fd28101e0e697a48e581fe31826f9a56..d97f2323af573ecf229f9d76b536634c57c26e17 100644 (file)
@@ -192,6 +192,7 @@ static int hidinput_setkeycode(struct input_dev *dev,
        return -EINVAL;
 }
 
+
 /**
  * hidinput_calc_abs_res - calculate an absolute axis resolution
  * @field: the HID report field to calculate resolution for
@@ -234,23 +235,17 @@ __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
        case ABS_MT_TOOL_Y:
        case ABS_MT_TOUCH_MAJOR:
        case ABS_MT_TOUCH_MINOR:
-               if (field->unit & 0xffffff00)           /* Not a length */
-                       return 0;
-               unit_exponent += hid_snto32(field->unit >> 4, 4) - 1;
-               switch (field->unit & 0xf) {
-               case 0x1:                               /* If centimeters */
+               if (field->unit == 0x11) {              /* If centimeters */
                        /* Convert to millimeters */
                        unit_exponent += 1;
-                       break;
-               case 0x3:                               /* If inches */
+               } else if (field->unit == 0x13) {       /* If inches */
                        /* Convert to millimeters */
                        prev = physical_extents;
                        physical_extents *= 254;
                        if (physical_extents < prev)
                                return 0;
                        unit_exponent -= 1;
-                       break;
-               default:
+               } else {
                        return 0;
                }
                break;
@@ -485,6 +480,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 +1235,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 +1248,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 602c188e9d86cafedde93366bf3d114e69c3e552..6101816a7ddd8a96ae8ad0e9ecfa297c29fa637f 100644 (file)
@@ -382,7 +382,7 @@ static ssize_t kone_sysfs_write_profilex(struct file *fp,
 }
 #define PROFILE_ATTR(number)                                   \
 static struct bin_attribute bin_attr_profile##number = {       \
-       .attr = { .name = "profile##number", .mode = 0660 },    \
+       .attr = { .name = "profile" #number, .mode = 0660 },    \
        .size = sizeof(struct kone_profile),                    \
        .read = kone_sysfs_read_profilex,                       \
        .write = kone_sysfs_write_profilex,                     \
index 5ddf605b6b890b15c2b9f94783072d951908e5db..5e99fcdc71b9cf0631cb7adcc8b61a22c36ae728 100644 (file)
@@ -229,13 +229,13 @@ static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
 
 #define PROFILE_ATTR(number)                                           \
 static struct bin_attribute bin_attr_profile##number##_settings = {    \
-       .attr = { .name = "profile##number##_settings", .mode = 0440 }, \
+       .attr = { .name = "profile" #number "_settings", .mode = 0440 },        \
        .size = KONEPLUS_SIZE_PROFILE_SETTINGS,                         \
        .read = koneplus_sysfs_read_profilex_settings,                  \
        .private = &profile_numbers[number-1],                          \
 };                                                                     \
 static struct bin_attribute bin_attr_profile##number##_buttons = {     \
-       .attr = { .name = "profile##number##_buttons", .mode = 0440 },  \
+       .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
        .size = KONEPLUS_SIZE_PROFILE_BUTTONS,                          \
        .read = koneplus_sysfs_read_profilex_buttons,                   \
        .private = &profile_numbers[number-1],                          \
index 515bc03136c0c6497b2ada738f6f8a10f7368311..0c8e1ef0b67d14fdb1c3bf2a6b575fdea94faf8e 100644 (file)
@@ -257,13 +257,13 @@ static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
 
 #define PROFILE_ATTR(number)                                           \
 static struct bin_attribute bin_attr_profile##number##_settings = {    \
-       .attr = { .name = "profile##number##_settings", .mode = 0440 }, \
+       .attr = { .name = "profile" #number "_settings", .mode = 0440 },        \
        .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,                         \
        .read = kovaplus_sysfs_read_profilex_settings,                  \
        .private = &profile_numbers[number-1],                          \
 };                                                                     \
 static struct bin_attribute bin_attr_profile##number##_buttons = {     \
-       .attr = { .name = "profile##number##_buttons", .mode = 0440 },  \
+       .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
        .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,                          \
        .read = kovaplus_sysfs_read_profilex_buttons,                   \
        .private = &profile_numbers[number-1],                          \
index 5a6dbbeee790d05ae7abbfb8e045b758b6a6f5ba..1a07e07d99a06c8972a2d80b8fefa8aa4f4b3848 100644 (file)
@@ -225,13 +225,13 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
 
 #define PROFILE_ATTR(number)                                           \
 static struct bin_attribute bin_attr_profile##number##_settings = {    \
-       .attr = { .name = "profile##number##_settings", .mode = 0440 }, \
+       .attr = { .name = "profile" #number "_settings", .mode = 0440 },        \
        .size = PYRA_SIZE_PROFILE_SETTINGS,                             \
        .read = pyra_sysfs_read_profilex_settings,                      \
        .private = &profile_numbers[number-1],                          \
 };                                                                     \
 static struct bin_attribute bin_attr_profile##number##_buttons = {     \
-       .attr = { .name = "profile##number##_buttons", .mode = 0440 },  \
+       .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
        .size = PYRA_SIZE_PROFILE_BUTTONS,                              \
        .read = pyra_sysfs_read_profilex_buttons,                       \
        .private = &profile_numbers[number-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 bd2bc4a1f3781e94897d9877064b553f18ea3604..1446f526ee8bbade2290b615fc14b6aae35dc09f 100644 (file)
@@ -455,12 +455,6 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem)
                return WIIMOTE_EXT_BALANCE_BOARD;
        if (rmem[4] == 0x01 && rmem[5] == 0x20)
                return WIIMOTE_EXT_PRO_CONTROLLER;
-       if (rmem[0] == 0x01 && rmem[1] == 0x00 &&
-           rmem[4] == 0x01 && rmem[5] == 0x03)
-               return WIIMOTE_EXT_GUITAR_HERO_DRUMS;
-       if (rmem[0] == 0x00 && rmem[1] == 0x00 &&
-           rmem[4] == 0x01 && rmem[5] == 0x03)
-               return WIIMOTE_EXT_GUITAR_HERO_GUITAR;
 
        return WIIMOTE_EXT_UNKNOWN;
 }
@@ -494,8 +488,6 @@ static bool wiimote_cmd_map_mp(struct wiimote_data *wdata, __u8 exttype)
        /* map MP with correct pass-through mode */
        switch (exttype) {
        case WIIMOTE_EXT_CLASSIC_CONTROLLER:
-       case WIIMOTE_EXT_GUITAR_HERO_DRUMS:
-       case WIIMOTE_EXT_GUITAR_HERO_GUITAR:
                wmem = 0x07;
                break;
        case WIIMOTE_EXT_NUNCHUK:
@@ -842,7 +834,8 @@ static void wiimote_init_set_type(struct wiimote_data *wdata,
                goto done;
        }
 
-       if (vendor == USB_VENDOR_ID_NINTENDO) {
+       if (vendor == USB_VENDOR_ID_NINTENDO ||
+           vendor == USB_VENDOR_ID_NINTENDO2) {
                if (product == USB_DEVICE_ID_NINTENDO_WIIMOTE) {
                        devtype = WIIMOTE_DEV_GEN10;
                        goto done;
@@ -1083,8 +1076,6 @@ static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = {
        [WIIMOTE_EXT_CLASSIC_CONTROLLER] = "Nintendo Wii Classic Controller",
        [WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board",
        [WIIMOTE_EXT_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller",
-       [WIIMOTE_EXT_GUITAR_HERO_DRUMS] = "Nintendo Wii Guitar Hero Drums",
-       [WIIMOTE_EXT_GUITAR_HERO_GUITAR] = "Nintendo Wii Guitar Hero Guitar",
 };
 
 /*
@@ -1670,10 +1661,6 @@ static ssize_t wiimote_ext_show(struct device *dev,
                return sprintf(buf, "balanceboard\n");
        case WIIMOTE_EXT_PRO_CONTROLLER:
                return sprintf(buf, "procontroller\n");
-       case WIIMOTE_EXT_GUITAR_HERO_DRUMS:
-               return sprintf(buf, "drums\n");
-       case WIIMOTE_EXT_GUITAR_HERO_GUITAR:
-               return sprintf(buf, "guitar\n");
        case WIIMOTE_EXT_UNKNOWN:
                /* fallthrough */
        default:
@@ -1869,6 +1856,8 @@ static void wiimote_hid_remove(struct hid_device *hdev)
 static const struct hid_device_id wiimote_hid_devices[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
                                USB_DEVICE_ID_NINTENDO_WIIMOTE) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO2,
+                               USB_DEVICE_ID_NINTENDO_WIIMOTE) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
                                USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
        { }
index 7e124c351e67e9b73d15e11fef42708e61ea61a4..71adf9e60b13f4aafa22ba94183bb4dcb8a3a21d 100644 (file)
@@ -119,12 +119,22 @@ static const struct wiimod_ops wiimod_keys = {
  * the rumble motor, this flag shouldn't be set.
  */
 
+/* used by wiimod_rumble and wiipro_rumble */
+static void wiimod_rumble_worker(struct work_struct *work)
+{
+       struct wiimote_data *wdata = container_of(work, struct wiimote_data,
+                                                 rumble_worker);
+
+       spin_lock_irq(&wdata->state.lock);
+       wiiproto_req_rumble(wdata, wdata->state.cache_rumble);
+       spin_unlock_irq(&wdata->state.lock);
+}
+
 static int wiimod_rumble_play(struct input_dev *dev, void *data,
                              struct ff_effect *eff)
 {
        struct wiimote_data *wdata = input_get_drvdata(dev);
        __u8 value;
-       unsigned long flags;
 
        /*
         * The wiimote supports only a single rumble motor so if any magnitude
@@ -137,9 +147,10 @@ static int wiimod_rumble_play(struct input_dev *dev, void *data,
        else
                value = 0;
 
-       spin_lock_irqsave(&wdata->state.lock, flags);
-       wiiproto_req_rumble(wdata, value);
-       spin_unlock_irqrestore(&wdata->state.lock, flags);
+       /* Locking state.lock here might deadlock with input_event() calls.
+        * schedule_work acts as barrier. Merging multiple changes is fine. */
+       wdata->state.cache_rumble = value;
+       schedule_work(&wdata->rumble_worker);
 
        return 0;
 }
@@ -147,6 +158,8 @@ static int wiimod_rumble_play(struct input_dev *dev, void *data,
 static int wiimod_rumble_probe(const struct wiimod_ops *ops,
                               struct wiimote_data *wdata)
 {
+       INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker);
+
        set_bit(FF_RUMBLE, wdata->input->ffbit);
        if (input_ff_create_memless(wdata->input, NULL, wiimod_rumble_play))
                return -ENOMEM;
@@ -159,6 +172,8 @@ static void wiimod_rumble_remove(const struct wiimod_ops *ops,
 {
        unsigned long flags;
 
+       cancel_work_sync(&wdata->rumble_worker);
+
        spin_lock_irqsave(&wdata->state.lock, flags);
        wiiproto_req_rumble(wdata, 0);
        spin_unlock_irqrestore(&wdata->state.lock, flags);
@@ -1731,7 +1746,6 @@ static int wiimod_pro_play(struct input_dev *dev, void *data,
 {
        struct wiimote_data *wdata = input_get_drvdata(dev);
        __u8 value;
-       unsigned long flags;
 
        /*
         * The wiimote supports only a single rumble motor so if any magnitude
@@ -1744,9 +1758,10 @@ static int wiimod_pro_play(struct input_dev *dev, void *data,
        else
                value = 0;
 
-       spin_lock_irqsave(&wdata->state.lock, flags);
-       wiiproto_req_rumble(wdata, value);
-       spin_unlock_irqrestore(&wdata->state.lock, flags);
+       /* Locking state.lock here might deadlock with input_event() calls.
+        * schedule_work acts as barrier. Merging multiple changes is fine. */
+       wdata->state.cache_rumble = value;
+       schedule_work(&wdata->rumble_worker);
 
        return 0;
 }
@@ -1756,6 +1771,8 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops,
 {
        int ret, i;
 
+       INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker);
+
        wdata->extension.input = input_allocate_device();
        if (!wdata->extension.input)
                return -ENOMEM;
@@ -1817,12 +1834,13 @@ static void wiimod_pro_remove(const struct wiimod_ops *ops,
        if (!wdata->extension.input)
                return;
 
+       input_unregister_device(wdata->extension.input);
+       wdata->extension.input = NULL;
+       cancel_work_sync(&wdata->rumble_worker);
+
        spin_lock_irqsave(&wdata->state.lock, flags);
        wiiproto_req_rumble(wdata, 0);
        spin_unlock_irqrestore(&wdata->state.lock, flags);
-
-       input_unregister_device(wdata->extension.input);
-       wdata->extension.input = NULL;
 }
 
 static const struct wiimod_ops wiimod_pro = {
@@ -1833,396 +1851,6 @@ static const struct wiimod_ops wiimod_pro = {
        .in_ext = wiimod_pro_in_ext,
 };
 
-/*
- * Drums
- * Guitar-Hero, Rock-Band and other games came bundled with drums which can
- * be plugged as extension to a Wiimote. Drum-reports are still not entirely
- * figured out, but the most important information is known.
- * We create a separate device for drums and report all information via this
- * input device.
- */
-
-static inline void wiimod_drums_report_pressure(struct wiimote_data *wdata,
-                                               __u8 none, __u8 which,
-                                               __u8 pressure, __u8 onoff,
-                                               __u8 *store, __u16 code,
-                                               __u8 which_code)
-{
-       static const __u8 default_pressure = 3;
-
-       if (!none && which == which_code) {
-               *store = pressure;
-               input_report_abs(wdata->extension.input, code, *store);
-       } else if (onoff != !!*store) {
-               *store = onoff ? default_pressure : 0;
-               input_report_abs(wdata->extension.input, code, *store);
-       }
-}
-
-static void wiimod_drums_in_ext(struct wiimote_data *wdata, const __u8 *ext)
-{
-       __u8 pressure, which, none, hhp, sx, sy;
-       __u8 o, r, y, g, b, bass, bm, bp;
-
-       /*   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    1   |  0  |  0  |              SX <5:0>             |
-        *    2   |  0  |  0  |              SY <5:0>             |
-        *   -----+-----+-----+-----------------------------+-----+
-        *    3   | HPP | NON |         WHICH <5:1>         |  ?  |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    4   |   SOFT <7:5>    |  0  |  1  |  1  |  0  |  ?  |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    5   |  ?  |  1  |  1  | B-  |  1  | B+  |  1  |  ?  |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    6   |  O  |  R  |  Y  |  G  |  B  | BSS |  1  |  1  |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        * All buttons are 0 if pressed
-        *
-        * With Motion+ enabled, the following bits will get invalid:
-        *   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    1   |  0  |  0  |              SX <5:1>       |XXXXX|
-        *    2   |  0  |  0  |              SY <5:1>       |XXXXX|
-        *   -----+-----+-----+-----------------------------+-----+
-        *    3   | HPP | NON |         WHICH <5:1>         |  ?  |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    4   |   SOFT <7:5>    |  0  |  1  |  1  |  0  |  ?  |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    5   |  ?  |  1  |  1  | B-  |  1  | B+  |  1  |XXXXX|
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    6   |  O  |  R  |  Y  |  G  |  B  | BSS |XXXXX|XXXXX|
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        */
-
-       pressure = 7 - (ext[3] >> 5);
-       which = (ext[2] >> 1) & 0x1f;
-       none = !!(ext[2] & 0x40);
-       hhp = !(ext[2] & 0x80);
-       sx = ext[0] & 0x3f;
-       sy = ext[1] & 0x3f;
-       o = !(ext[5] & 0x80);
-       r = !(ext[5] & 0x40);
-       y = !(ext[5] & 0x20);
-       g = !(ext[5] & 0x10);
-       b = !(ext[5] & 0x08);
-       bass = !(ext[5] & 0x04);
-       bm = !(ext[4] & 0x10);
-       bp = !(ext[4] & 0x04);
-
-       wiimod_drums_report_pressure(wdata, none, which, pressure,
-                                    o, &wdata->state.pressure_drums[0],
-                                    ABS_CYMBAL_RIGHT, 0x0e);
-       wiimod_drums_report_pressure(wdata, none, which, pressure,
-                                    r, &wdata->state.pressure_drums[1],
-                                    ABS_TOM_LEFT, 0x19);
-       wiimod_drums_report_pressure(wdata, none, which, pressure,
-                                    y, &wdata->state.pressure_drums[2],
-                                    ABS_CYMBAL_LEFT, 0x11);
-       wiimod_drums_report_pressure(wdata, none, which, pressure,
-                                    g, &wdata->state.pressure_drums[3],
-                                    ABS_TOM_FAR_RIGHT, 0x12);
-       wiimod_drums_report_pressure(wdata, none, which, pressure,
-                                    b, &wdata->state.pressure_drums[4],
-                                    ABS_TOM_RIGHT, 0x0f);
-
-       /* Bass shares pressure with hi-hat (set via hhp) */
-       wiimod_drums_report_pressure(wdata, none, hhp ? 0xff : which, pressure,
-                                    bass, &wdata->state.pressure_drums[5],
-                                    ABS_BASS, 0x1b);
-       /* Hi-hat has no on/off values, just pressure. Force to off/0. */
-       wiimod_drums_report_pressure(wdata, none, hhp ? which : 0xff, pressure,
-                                    0, &wdata->state.pressure_drums[6],
-                                    ABS_HI_HAT, 0x0e);
-
-       input_report_abs(wdata->extension.input, ABS_X, sx - 0x20);
-       input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20);
-
-       input_report_key(wdata->extension.input, BTN_START, bp);
-       input_report_key(wdata->extension.input, BTN_SELECT, bm);
-
-       input_sync(wdata->extension.input);
-}
-
-static int wiimod_drums_open(struct input_dev *dev)
-{
-       struct wiimote_data *wdata = input_get_drvdata(dev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&wdata->state.lock, flags);
-       wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
-       wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
-       spin_unlock_irqrestore(&wdata->state.lock, flags);
-
-       return 0;
-}
-
-static void wiimod_drums_close(struct input_dev *dev)
-{
-       struct wiimote_data *wdata = input_get_drvdata(dev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&wdata->state.lock, flags);
-       wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
-       wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
-       spin_unlock_irqrestore(&wdata->state.lock, flags);
-}
-
-static int wiimod_drums_probe(const struct wiimod_ops *ops,
-                             struct wiimote_data *wdata)
-{
-       int ret;
-
-       wdata->extension.input = input_allocate_device();
-       if (!wdata->extension.input)
-               return -ENOMEM;
-
-       input_set_drvdata(wdata->extension.input, wdata);
-       wdata->extension.input->open = wiimod_drums_open;
-       wdata->extension.input->close = wiimod_drums_close;
-       wdata->extension.input->dev.parent = &wdata->hdev->dev;
-       wdata->extension.input->id.bustype = wdata->hdev->bus;
-       wdata->extension.input->id.vendor = wdata->hdev->vendor;
-       wdata->extension.input->id.product = wdata->hdev->product;
-       wdata->extension.input->id.version = wdata->hdev->version;
-       wdata->extension.input->name = WIIMOTE_NAME " Drums";
-
-       set_bit(EV_KEY, wdata->extension.input->evbit);
-       set_bit(BTN_START, wdata->extension.input->keybit);
-       set_bit(BTN_SELECT, wdata->extension.input->keybit);
-
-       set_bit(EV_ABS, wdata->extension.input->evbit);
-       set_bit(ABS_X, wdata->extension.input->absbit);
-       set_bit(ABS_Y, wdata->extension.input->absbit);
-       set_bit(ABS_TOM_LEFT, wdata->extension.input->absbit);
-       set_bit(ABS_TOM_RIGHT, wdata->extension.input->absbit);
-       set_bit(ABS_TOM_FAR_RIGHT, wdata->extension.input->absbit);
-       set_bit(ABS_CYMBAL_LEFT, wdata->extension.input->absbit);
-       set_bit(ABS_CYMBAL_RIGHT, wdata->extension.input->absbit);
-       set_bit(ABS_BASS, wdata->extension.input->absbit);
-       set_bit(ABS_HI_HAT, wdata->extension.input->absbit);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_X, -32, 31, 1, 1);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_Y, -32, 31, 1, 1);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_TOM_LEFT, 0, 7, 0, 0);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_TOM_RIGHT, 0, 7, 0, 0);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_TOM_FAR_RIGHT, 0, 7, 0, 0);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_CYMBAL_LEFT, 0, 7, 0, 0);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_CYMBAL_RIGHT, 0, 7, 0, 0);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_BASS, 0, 7, 0, 0);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_HI_HAT, 0, 7, 0, 0);
-
-       ret = input_register_device(wdata->extension.input);
-       if (ret)
-               goto err_free;
-
-       return 0;
-
-err_free:
-       input_free_device(wdata->extension.input);
-       wdata->extension.input = NULL;
-       return ret;
-}
-
-static void wiimod_drums_remove(const struct wiimod_ops *ops,
-                               struct wiimote_data *wdata)
-{
-       if (!wdata->extension.input)
-               return;
-
-       input_unregister_device(wdata->extension.input);
-       wdata->extension.input = NULL;
-}
-
-static const struct wiimod_ops wiimod_drums = {
-       .flags = 0,
-       .arg = 0,
-       .probe = wiimod_drums_probe,
-       .remove = wiimod_drums_remove,
-       .in_ext = wiimod_drums_in_ext,
-};
-
-/*
- * Guitar
- * Guitar-Hero, Rock-Band and other games came bundled with guitars which can
- * be plugged as extension to a Wiimote.
- * We create a separate device for guitars and report all information via this
- * input device.
- */
-
-static void wiimod_guitar_in_ext(struct wiimote_data *wdata, const __u8 *ext)
-{
-       __u8 sx, sy, tb, wb, bd, bm, bp, bo, br, bb, bg, by, bu;
-
-       /*   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    1   |  0  |  0  |              SX <5:0>             |
-        *    2   |  0  |  0  |              SY <5:0>             |
-        *   -----+-----+-----+-----+-----------------------------+
-        *    3   |  0  |  0  |  0  |      TB <4:0>               |
-        *   -----+-----+-----+-----+-----------------------------+
-        *    4   |  0  |  0  |  0  |      WB <4:0>               |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    5   |  1  | BD  |  1  | B-  |  1  | B+  |  1  |  1  |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    6   | BO  | BR  | BB  | BG  | BY  |  1  |  1  | BU  |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        * All buttons are 0 if pressed
-        *
-        * With Motion+ enabled, the following bits will get invalid:
-        *   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    1   |  0  |  0  |              SX <5:1>       |XXXXX|
-        *    2   |  0  |  0  |              SY <5:1>       |XXXXX|
-        *   -----+-----+-----+-----+-----------------------+-----+
-        *    3   |  0  |  0  |  0  |      TB <4:0>               |
-        *   -----+-----+-----+-----+-----------------------------+
-        *    4   |  0  |  0  |  0  |      WB <4:0>               |
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    5   |  1  | BD  |  1  | B-  |  1  | B+  |  1  |XXXXX|
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        *    6   | BO  | BR  | BB  | BG  | BY  |  1  |XXXXX|XXXXX|
-        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
-        */
-
-       sx = ext[0] & 0x3f;
-       sy = ext[1] & 0x3f;
-       tb = ext[2] & 0x1f;
-       wb = ext[3] & 0x1f;
-       bd = !(ext[4] & 0x40);
-       bm = !(ext[4] & 0x10);
-       bp = !(ext[4] & 0x04);
-       bo = !(ext[5] & 0x80);
-       br = !(ext[5] & 0x40);
-       bb = !(ext[5] & 0x20);
-       bg = !(ext[5] & 0x10);
-       by = !(ext[5] & 0x08);
-       bu = !(ext[5] & 0x01);
-
-       input_report_abs(wdata->extension.input, ABS_X, sx - 0x20);
-       input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20);
-       input_report_abs(wdata->extension.input, ABS_FRET_BOARD, tb);
-       input_report_abs(wdata->extension.input, ABS_WHAMMY_BAR, wb - 0x10);
-
-       input_report_key(wdata->extension.input, BTN_MODE, bm);
-       input_report_key(wdata->extension.input, BTN_START, bp);
-       input_report_key(wdata->extension.input, BTN_STRUM_BAR_UP, bu);
-       input_report_key(wdata->extension.input, BTN_STRUM_BAR_DOWN, bd);
-       input_report_key(wdata->extension.input, BTN_FRET_FAR_UP, bg);
-       input_report_key(wdata->extension.input, BTN_FRET_UP, br);
-       input_report_key(wdata->extension.input, BTN_FRET_MID, by);
-       input_report_key(wdata->extension.input, BTN_FRET_LOW, bb);
-       input_report_key(wdata->extension.input, BTN_FRET_FAR_LOW, bo);
-
-       input_sync(wdata->extension.input);
-}
-
-static int wiimod_guitar_open(struct input_dev *dev)
-{
-       struct wiimote_data *wdata = input_get_drvdata(dev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&wdata->state.lock, flags);
-       wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
-       wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
-       spin_unlock_irqrestore(&wdata->state.lock, flags);
-
-       return 0;
-}
-
-static void wiimod_guitar_close(struct input_dev *dev)
-{
-       struct wiimote_data *wdata = input_get_drvdata(dev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&wdata->state.lock, flags);
-       wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
-       wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
-       spin_unlock_irqrestore(&wdata->state.lock, flags);
-}
-
-static int wiimod_guitar_probe(const struct wiimod_ops *ops,
-                              struct wiimote_data *wdata)
-{
-       int ret;
-
-       wdata->extension.input = input_allocate_device();
-       if (!wdata->extension.input)
-               return -ENOMEM;
-
-       input_set_drvdata(wdata->extension.input, wdata);
-       wdata->extension.input->open = wiimod_guitar_open;
-       wdata->extension.input->close = wiimod_guitar_close;
-       wdata->extension.input->dev.parent = &wdata->hdev->dev;
-       wdata->extension.input->id.bustype = wdata->hdev->bus;
-       wdata->extension.input->id.vendor = wdata->hdev->vendor;
-       wdata->extension.input->id.product = wdata->hdev->product;
-       wdata->extension.input->id.version = wdata->hdev->version;
-       wdata->extension.input->name = WIIMOTE_NAME " Guitar";
-
-       set_bit(EV_KEY, wdata->extension.input->evbit);
-       set_bit(BTN_MODE, wdata->extension.input->keybit);
-       set_bit(BTN_START, wdata->extension.input->keybit);
-       set_bit(BTN_FRET_FAR_UP, wdata->extension.input->keybit);
-       set_bit(BTN_FRET_UP, wdata->extension.input->keybit);
-       set_bit(BTN_FRET_MID, wdata->extension.input->keybit);
-       set_bit(BTN_FRET_LOW, wdata->extension.input->keybit);
-       set_bit(BTN_FRET_FAR_LOW, wdata->extension.input->keybit);
-       set_bit(BTN_STRUM_BAR_UP, wdata->extension.input->keybit);
-       set_bit(BTN_STRUM_BAR_DOWN, wdata->extension.input->keybit);
-
-       set_bit(EV_ABS, wdata->extension.input->evbit);
-       set_bit(ABS_X, wdata->extension.input->absbit);
-       set_bit(ABS_Y, wdata->extension.input->absbit);
-       set_bit(ABS_FRET_BOARD, wdata->extension.input->absbit);
-       set_bit(ABS_WHAMMY_BAR, wdata->extension.input->absbit);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_X, -32, 31, 1, 1);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_Y, -32, 31, 1, 1);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_FRET_BOARD, 0, 0x1f, 1, 1);
-       input_set_abs_params(wdata->extension.input,
-                            ABS_WHAMMY_BAR, 0, 0x0f, 1, 1);
-
-       ret = input_register_device(wdata->extension.input);
-       if (ret)
-               goto err_free;
-
-       return 0;
-
-err_free:
-       input_free_device(wdata->extension.input);
-       wdata->extension.input = NULL;
-       return ret;
-}
-
-static void wiimod_guitar_remove(const struct wiimod_ops *ops,
-                                struct wiimote_data *wdata)
-{
-       if (!wdata->extension.input)
-               return;
-
-       input_unregister_device(wdata->extension.input);
-       wdata->extension.input = NULL;
-}
-
-static const struct wiimod_ops wiimod_guitar = {
-       .flags = 0,
-       .arg = 0,
-       .probe = wiimod_guitar_probe,
-       .remove = wiimod_guitar_remove,
-       .in_ext = wiimod_guitar_in_ext,
-};
-
 /*
  * Builtin Motion Plus
  * This module simply sets the WIIPROTO_FLAG_BUILTIN_MP protocol flag which
@@ -2473,6 +2101,4 @@ const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = {
        [WIIMOTE_EXT_CLASSIC_CONTROLLER] = &wiimod_classic,
        [WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard,
        [WIIMOTE_EXT_PRO_CONTROLLER] = &wiimod_pro,
-       [WIIMOTE_EXT_GUITAR_HERO_DRUMS] = &wiimod_drums,
-       [WIIMOTE_EXT_GUITAR_HERO_GUITAR] = &wiimod_guitar,
 };
index 379cdfb6bd258bea39c04341cf8d497b206c730e..75db0c4000377f03bf262eb66a5492046aa012c8 100644 (file)
@@ -88,8 +88,6 @@ enum wiimote_exttype {
        WIIMOTE_EXT_CLASSIC_CONTROLLER,
        WIIMOTE_EXT_BALANCE_BOARD,
        WIIMOTE_EXT_PRO_CONTROLLER,
-       WIIMOTE_EXT_GUITAR_HERO_DRUMS,
-       WIIMOTE_EXT_GUITAR_HERO_GUITAR,
        WIIMOTE_EXT_NUM,
 };
 
@@ -135,14 +133,15 @@ struct wiimote_state {
        __u8 *cmd_read_buf;
        __u8 cmd_read_size;
 
-       /* calibration data */
+       /* calibration/cache data */
        __u16 calib_bboard[4][3];
-       __u8 pressure_drums[7];
+       __u8 cache_rumble;
 };
 
 struct wiimote_data {
        struct hid_device *hdev;
        struct input_dev *input;
+       struct work_struct rumble_worker;
        struct led_classdev *leds[4];
        struct input_dev *accel;
        struct input_dev *ir;
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 8918dd12bb6915d08ab588e04b22b64a24d6e827..6a6dd5cd783343c0804f26311674458a19d6519b 100644 (file)
@@ -308,18 +308,25 @@ static int hidraw_fasync(int fd, struct file *file, int on)
 static void drop_ref(struct hidraw *hidraw, int exists_bit)
 {
        if (exists_bit) {
-               hid_hw_close(hidraw->hid);
                hidraw->exist = 0;
-               if (hidraw->open)
+               if (hidraw->open) {
+                       hid_hw_close(hidraw->hid);
                        wake_up_interruptible(&hidraw->wait);
+               }
        } else {
                --hidraw->open;
        }
-
-       if (!hidraw->open && !hidraw->exist) {
-               device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
-               hidraw_table[hidraw->minor] = NULL;
-               kfree(hidraw);
+       if (!hidraw->open) {
+               if (!hidraw->exist) {
+                       device_destroy(hidraw_class,
+                                       MKDEV(hidraw_major, hidraw->minor));
+                       hidraw_table[hidraw->minor] = NULL;
+                       kfree(hidraw);
+               } else {
+                       /* close device for last reader */
+                       hid_hw_power(hidraw->hid, PM_HINT_NORMAL);
+                       hid_hw_close(hidraw->hid);
+               }
        }
 }
 
index 5bf2fb785844919bbc27ad20160b98a998102aa5..93b00d76374cee2b82be0a9deab2a0f8d7c6755b 100644 (file)
@@ -615,7 +615,7 @@ static const struct file_operations uhid_fops = {
 
 static struct miscdevice uhid_misc = {
        .fops           = &uhid_fops,
-       .minor          = MISC_DYNAMIC_MINOR,
+       .minor          = UHID_MINOR,
        .name           = UHID_NAME,
 };
 
@@ -634,4 +634,5 @@ module_exit(uhid_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
 MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
+MODULE_ALIAS_MISCDEV(UHID_MINOR);
 MODULE_ALIAS("devname:" UHID_NAME);
index 07345521f4210f4988627cff4421beedc96d1c06..3fca3be08337d76fdd8ecaec09c3d1693b0ac4ef 100644 (file)
@@ -110,6 +110,9 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS2, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_SIS, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS },
 
        { 0, 0 }
 };
index 8f4743ab5fb279ae416fbce5ff4e16e58db45eaf..936093e0271e3c7fffccce7fe0e688c4d6f3ad01 100644 (file)
@@ -195,7 +195,7 @@ int vmbus_connect(void)
 
        do {
                ret = vmbus_negotiate_version(msginfo, version);
-               if (ret)
+               if (ret == -ETIMEDOUT)
                        goto cleanup;
 
                if (vmbus_connection.conn_state == CONNECTED)
index 28b03325b8729ffdf2d3356538dc2515b5af5de2..09988b2896226552e4be5cd69d5f09ba3f842d11 100644 (file)
 /*
  * Pre win8 version numbers used in ws2008 and ws 2008 r2 (win7)
  */
+#define WS2008_SRV_MAJOR       1
+#define WS2008_SRV_MINOR       0
+#define WS2008_SRV_VERSION     (WS2008_SRV_MAJOR << 16 | WS2008_SRV_MINOR)
+
 #define WIN7_SRV_MAJOR   3
 #define WIN7_SRV_MINOR   0
-#define WIN7_SRV_MAJOR_MINOR     (WIN7_SRV_MAJOR << 16 | WIN7_SRV_MINOR)
+#define WIN7_SRV_VERSION     (WIN7_SRV_MAJOR << 16 | WIN7_SRV_MINOR)
 
 #define WIN8_SRV_MAJOR   4
 #define WIN8_SRV_MINOR   0
-#define WIN8_SRV_MAJOR_MINOR     (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
+#define WIN8_SRV_VERSION     (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
 
 /*
  * Global state maintained for transaction that is being processed.
@@ -587,6 +591,8 @@ void hv_kvp_onchannelcallback(void *context)
 
        struct icmsg_hdr *icmsghdrp;
        struct icmsg_negotiate *negop = NULL;
+       int util_fw_version;
+       int kvp_srv_version;
 
        if (kvp_transaction.active) {
                /*
@@ -606,17 +612,26 @@ void hv_kvp_onchannelcallback(void *context)
 
                if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
                        /*
-                        * We start with win8 version and if the host cannot
-                        * support that we use the previous version.
+                        * Based on the host, select appropriate
+                        * framework and service versions we will
+                        * negotiate.
                         */
-                       if (vmbus_prep_negotiate_resp(icmsghdrp, negop,
-                                recv_buffer, UTIL_FW_MAJOR_MINOR,
-                                WIN8_SRV_MAJOR_MINOR))
-                               goto done;
-
+                       switch (vmbus_proto_version) {
+                       case (VERSION_WS2008):
+                               util_fw_version = UTIL_WS2K8_FW_VERSION;
+                               kvp_srv_version = WS2008_SRV_VERSION;
+                               break;
+                       case (VERSION_WIN7):
+                               util_fw_version = UTIL_FW_VERSION;
+                               kvp_srv_version = WIN7_SRV_VERSION;
+                               break;
+                       default:
+                               util_fw_version = UTIL_FW_VERSION;
+                               kvp_srv_version = WIN8_SRV_VERSION;
+                       }
                        vmbus_prep_negotiate_resp(icmsghdrp, negop,
-                                recv_buffer, UTIL_FW_MAJOR_MINOR,
-                                WIN7_SRV_MAJOR_MINOR);
+                                recv_buffer, util_fw_version,
+                                kvp_srv_version);
 
                } else {
                        kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
@@ -649,7 +664,6 @@ void hv_kvp_onchannelcallback(void *context)
                        return;
 
                }
-done:
 
                icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
                        | ICMSGHDRFLAG_RESPONSE;
index e4572f3f2834fe917c5f4dbf097a30cbc8f3b383..0c354622437681d1b6dd157f718bb27cf8dbdbed 100644 (file)
@@ -26,7 +26,7 @@
 
 #define VSS_MAJOR  5
 #define VSS_MINOR  0
-#define VSS_MAJOR_MINOR    (VSS_MAJOR << 16 | VSS_MINOR)
+#define VSS_VERSION    (VSS_MAJOR << 16 | VSS_MINOR)
 
 
 
@@ -190,8 +190,8 @@ void hv_vss_onchannelcallback(void *context)
 
                if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
                        vmbus_prep_negotiate_resp(icmsghdrp, negop,
-                                recv_buffer, UTIL_FW_MAJOR_MINOR,
-                                VSS_MAJOR_MINOR);
+                                recv_buffer, UTIL_FW_VERSION,
+                                VSS_VERSION);
                } else {
                        vss_msg = (struct hv_vss_msg *)&recv_buffer[
                                sizeof(struct vmbuspipe_hdr) +
index cb82233541b196a53177007ebb4520a9e4112442..273e3ddb3a20b00c5d1ae03bab6368c5fcfbc26f 100644 (file)
 #include <linux/reboot.h>
 #include <linux/hyperv.h>
 
-#define SHUTDOWN_MAJOR 3
-#define SHUTDOWN_MINOR  0
-#define SHUTDOWN_MAJOR_MINOR   (SHUTDOWN_MAJOR << 16 | SHUTDOWN_MINOR)
 
-#define TIMESYNCH_MAJOR        3
-#define TIMESYNCH_MINOR 0
-#define TIMESYNCH_MAJOR_MINOR  (TIMESYNCH_MAJOR << 16 | TIMESYNCH_MINOR)
+#define SD_MAJOR       3
+#define SD_MINOR       0
+#define SD_VERSION     (SD_MAJOR << 16 | SD_MINOR)
 
-#define HEARTBEAT_MAJOR        3
-#define HEARTBEAT_MINOR 0
-#define HEARTBEAT_MAJOR_MINOR  (HEARTBEAT_MAJOR << 16 | HEARTBEAT_MINOR)
+#define SD_WS2008_MAJOR                1
+#define SD_WS2008_VERSION      (SD_WS2008_MAJOR << 16 | SD_MINOR)
+
+#define TS_MAJOR       3
+#define TS_MINOR       0
+#define TS_VERSION     (TS_MAJOR << 16 | TS_MINOR)
+
+#define TS_WS2008_MAJOR                1
+#define TS_WS2008_VERSION      (TS_WS2008_MAJOR << 16 | TS_MINOR)
+
+#define HB_MAJOR       3
+#define HB_MINOR 0
+#define HB_VERSION     (HB_MAJOR << 16 | HB_MINOR)
+
+#define HB_WS2008_MAJOR        1
+#define HB_WS2008_VERSION      (HB_WS2008_MAJOR << 16 | HB_MINOR)
+
+static int sd_srv_version;
+static int ts_srv_version;
+static int hb_srv_version;
+static int util_fw_version;
 
 static void shutdown_onchannelcallback(void *context);
 static struct hv_util_service util_shutdown = {
@@ -99,8 +114,8 @@ static void shutdown_onchannelcallback(void *context)
 
                if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
                        vmbus_prep_negotiate_resp(icmsghdrp, negop,
-                                       shut_txf_buf, UTIL_FW_MAJOR_MINOR,
-                                       SHUTDOWN_MAJOR_MINOR);
+                                       shut_txf_buf, util_fw_version,
+                                       sd_srv_version);
                } else {
                        shutdown_msg =
                                (struct shutdown_msg_data *)&shut_txf_buf[
@@ -216,6 +231,7 @@ static void timesync_onchannelcallback(void *context)
        struct icmsg_hdr *icmsghdrp;
        struct ictimesync_data *timedatap;
        u8 *time_txf_buf = util_timesynch.recv_buffer;
+       struct icmsg_negotiate *negop = NULL;
 
        vmbus_recvpacket(channel, time_txf_buf,
                         PAGE_SIZE, &recvlen, &requestid);
@@ -225,9 +241,10 @@ static void timesync_onchannelcallback(void *context)
                                sizeof(struct vmbuspipe_hdr)];
 
                if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
-                       vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf,
-                                               UTIL_FW_MAJOR_MINOR,
-                                               TIMESYNCH_MAJOR_MINOR);
+                       vmbus_prep_negotiate_resp(icmsghdrp, negop,
+                                               time_txf_buf,
+                                               util_fw_version,
+                                               ts_srv_version);
                } else {
                        timedatap = (struct ictimesync_data *)&time_txf_buf[
                                sizeof(struct vmbuspipe_hdr) +
@@ -257,6 +274,7 @@ static void heartbeat_onchannelcallback(void *context)
        struct icmsg_hdr *icmsghdrp;
        struct heartbeat_msg_data *heartbeat_msg;
        u8 *hbeat_txf_buf = util_heartbeat.recv_buffer;
+       struct icmsg_negotiate *negop = NULL;
 
        vmbus_recvpacket(channel, hbeat_txf_buf,
                         PAGE_SIZE, &recvlen, &requestid);
@@ -266,9 +284,9 @@ static void heartbeat_onchannelcallback(void *context)
                                sizeof(struct vmbuspipe_hdr)];
 
                if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
-                       vmbus_prep_negotiate_resp(icmsghdrp, NULL,
-                               hbeat_txf_buf, UTIL_FW_MAJOR_MINOR,
-                               HEARTBEAT_MAJOR_MINOR);
+                       vmbus_prep_negotiate_resp(icmsghdrp, negop,
+                               hbeat_txf_buf, util_fw_version,
+                               hb_srv_version);
                } else {
                        heartbeat_msg =
                                (struct heartbeat_msg_data *)&hbeat_txf_buf[
@@ -321,6 +339,25 @@ static int util_probe(struct hv_device *dev,
                goto error;
 
        hv_set_drvdata(dev, srv);
+       /*
+        * Based on the host; initialize the framework and
+        * service version numbers we will negotiate.
+        */
+       switch (vmbus_proto_version) {
+       case (VERSION_WS2008):
+               util_fw_version = UTIL_WS2K8_FW_VERSION;
+               sd_srv_version = SD_WS2008_VERSION;
+               ts_srv_version = TS_WS2008_VERSION;
+               hb_srv_version = HB_WS2008_VERSION;
+               break;
+
+       default:
+               util_fw_version = UTIL_FW_VERSION;
+               sd_srv_version = SD_VERSION;
+               ts_srv_version = TS_VERSION;
+               hb_srv_version = HB_VERSION;
+       }
+
        return 0;
 
 error:
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 62c2e32e25ef6823290380074d50829af30e5751..3288f13d2d871679b5eac9d6dd019675ede3c0d5 100644 (file)
@@ -230,6 +230,7 @@ static int send_argument(const char *key)
 
 static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
 {
+       u8 status, data = 0;
        int i;
 
        if (send_command(cmd) || send_argument(key)) {
@@ -237,6 +238,7 @@ static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
                return -EIO;
        }
 
+       /* This has no effect on newer (2012) SMCs */
        if (send_byte(len, APPLESMC_DATA_PORT)) {
                pr_warn("%.4s: read len fail\n", key);
                return -EIO;
@@ -250,6 +252,17 @@ static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
                buffer[i] = inb(APPLESMC_DATA_PORT);
        }
 
+       /* Read the data port until bit0 is cleared */
+       for (i = 0; i < 16; i++) {
+               udelay(APPLESMC_MIN_WAIT);
+               status = inb(APPLESMC_CMD_PORT);
+               if (!(status & 0x01))
+                       break;
+               data = inb(APPLESMC_DATA_PORT);
+       }
+       if (i)
+               pr_warn("flushed %d bytes, last value is: %d\n", i, data);
+
        return 0;
 }
 
@@ -525,16 +538,25 @@ static int applesmc_init_smcreg_try(void)
 {
        struct applesmc_registers *s = &smcreg;
        bool left_light_sensor, right_light_sensor;
+       unsigned int count;
        u8 tmp[1];
        int ret;
 
        if (s->init_complete)
                return 0;
 
-       ret = read_register_count(&s->key_count);
+       ret = read_register_count(&count);
        if (ret)
                return ret;
 
+       if (s->cache && s->key_count != count) {
+               pr_warn("key count changed from %d to %d\n",
+                       s->key_count, count);
+               kfree(s->cache);
+               s->cache = NULL;
+       }
+       s->key_count = count;
+
        if (!s->cache)
                s->cache = kcalloc(s->key_count, sizeof(*s->cache), GFP_KERNEL);
        if (!s->cache)
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 936898f82f94d140ab00d0b58d78bc195d23e480..82e661e8241b7a15cf8c32ce57a048429704a2cd 100644 (file)
@@ -49,7 +49,7 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 #define EMC6W201_REG_TEMP_HIGH(nr)     (0x57 + (nr) * 2)
 #define EMC6W201_REG_FAN_MIN(nr)       (0x62 + (nr) * 2)
 
-enum { input, min, max } subfeature;
+enum subfeature { input, min, max };
 
 /*
  * Per-device data
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 0b804895be43361a9230b4632e101945091298ad..5febb43cb4c1032de659cbf3ec3ffa652c8c832f 100644 (file)
@@ -2,7 +2,7 @@
  * w83792d.c - Part of lm_sensors, Linux kernel modules for hardware
  *            monitoring
  * Copyright (C) 2004, 2005 Winbond Electronics Corp.
- *                         Chunhao Huang <DZShen@Winbond.com.tw>,
+ *                         Shane Huang,
  *                         Rudolf Marek <r.marek@assembler.cz>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -1665,6 +1665,6 @@ static void w83792d_print_debug(struct w83792d_data *data, struct device *dev)
 
 module_i2c_driver(w83792d_driver);
 
-MODULE_AUTHOR("Chunhao Huang @ Winbond <DZShen@Winbond.com.tw>");
+MODULE_AUTHOR("Shane Huang (Winbond)");
 MODULE_DESCRIPTION("W83792AD/D driver for linux-2.6");
 MODULE_LICENSE("GPL");
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 dbecf08399f86dd30baa7fa7b8964e2daf616bcb..5888feef1ac5a959b5f0471a3fb71b9a2b00bada 100644 (file)
@@ -98,6 +98,8 @@
 
 #define DW_IC_ERR_TX_ABRT      0x1
 
+#define DW_IC_TAR_10BITADDR_MASTER BIT(12)
+
 /*
  * status codes
  */
@@ -388,22 +390,34 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
 static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
 {
        struct i2c_msg *msgs = dev->msgs;
-       u32 ic_con;
+       u32 ic_con, ic_tar = 0;
 
        /* Disable the adapter */
        __i2c_dw_enable(dev, false);
 
-       /* set the slave (target) address */
-       dw_writel(dev, msgs[dev->msg_write_idx].addr, DW_IC_TAR);
-
        /* if the slave address is ten bit address, enable 10BITADDR */
        ic_con = dw_readl(dev, DW_IC_CON);
-       if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
+       if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) {
                ic_con |= DW_IC_CON_10BITADDR_MASTER;
-       else
+               /*
+                * If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing
+                * mode has to be enabled via bit 12 of IC_TAR register.
+                * We set it always as I2C_DYNAMIC_TAR_UPDATE can't be
+                * detected from registers.
+                */
+               ic_tar = DW_IC_TAR_10BITADDR_MASTER;
+       } else {
                ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
+       }
+
        dw_writel(dev, ic_con, DW_IC_CON);
 
+       /*
+        * Set the slave (target) address and enable 10-bit addressing mode
+        * if applicable.
+        */
+       dw_writel(dev, msgs[dev->msg_write_idx].addr | ic_tar, DW_IC_TAR);
+
        /* Enable the adapter */
        __i2c_dw_enable(dev, true);
 
index 4c1b60539a2515c34ee4df0e7c353dbd7860dc56..0aa01136f8d955148d984ac00e06ffb9e8ce1196 100644 (file)
@@ -270,7 +270,8 @@ static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume);
 MODULE_ALIAS("platform:i2c_designware");
 
 static struct platform_driver dw_i2c_driver = {
-       .remove         = dw_i2c_remove,
+       .probe = dw_i2c_probe,
+       .remove = dw_i2c_remove,
        .driver         = {
                .name   = "i2c_designware",
                .owner  = THIS_MODULE,
@@ -282,7 +283,7 @@ static struct platform_driver dw_i2c_driver = {
 
 static int __init dw_i2c_init_driver(void)
 {
-       return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
+       return platform_driver_register(&dw_i2c_driver);
 }
 subsys_initcall(dw_i2c_init_driver);
 
index ccf46656bdad9182e2d75d6c1f3dbf42ea0c32c6..1d7efa3169cd772ed2ba580b0c8cfd149eee09d5 100644 (file)
@@ -365,7 +365,7 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
        clk_disable_unprepare(i2c_imx->clk);
 }
 
-static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
+static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
                                                        unsigned int rate)
 {
        struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div;
@@ -589,7 +589,7 @@ static struct i2c_algorithm i2c_imx_algo = {
        .functionality  = i2c_imx_func,
 };
 
-static int __init i2c_imx_probe(struct platform_device *pdev)
+static int i2c_imx_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id = of_match_device(i2c_imx_dt_ids,
                                                           &pdev->dev);
@@ -697,7 +697,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
        return 0;   /* Return OK */
 }
 
-static int __exit i2c_imx_remove(struct platform_device *pdev)
+static int i2c_imx_remove(struct platform_device *pdev)
 {
        struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
 
@@ -715,7 +715,8 @@ static int __exit i2c_imx_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver i2c_imx_driver = {
-       .remove         = __exit_p(i2c_imx_remove),
+       .probe = i2c_imx_probe,
+       .remove = i2c_imx_remove,
        .driver = {
                .name   = DRIVER_NAME,
                .owner  = THIS_MODULE,
@@ -726,7 +727,7 @@ static struct platform_driver i2c_imx_driver = {
 
 static int __init i2c_adap_imx_init(void)
 {
-       return platform_driver_probe(&i2c_imx_driver, i2c_imx_probe);
+       return platform_driver_register(&i2c_imx_driver);
 }
 subsys_initcall(i2c_adap_imx_init);
 
index 8ed79a086f858012b0f22b291834a5fb357d075c..1672effbcebb23894b99deac27bb84d595fa28d2 100644 (file)
@@ -393,6 +393,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
 
        desc = &priv->hw[priv->head];
 
+       /* Initialize the DMA buffer */
+       memset(priv->dma_buffer, 0, sizeof(priv->dma_buffer));
+
        /* Initialize the descriptor */
        memset(desc, 0, sizeof(struct ismt_desc));
        desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write);
index 7f3a4744349476f941a4500c9edc6a65a6da0fe2..d3e9cc3153a973dc62f99d7d607e003179f41f9d 100644 (file)
@@ -234,9 +234,9 @@ static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data)
                ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_WR |
                    (msg->len - 1) << MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT;
 
-               writel_relaxed(data_reg_lo,
+               writel(data_reg_lo,
                        drv_data->reg_base + MV64XXX_I2C_REG_TX_DATA_LO);
-               writel_relaxed(data_reg_hi,
+               writel(data_reg_hi,
                        drv_data->reg_base + MV64XXX_I2C_REG_TX_DATA_HI);
 
        } else {
@@ -697,6 +697,7 @@ static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
 MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
 
 #ifdef CONFIG_OF
+#ifdef CONFIG_HAVE_CLK
 static int
 mv64xxx_calc_freq(const int tclk, const int n, const int m)
 {
@@ -726,16 +727,12 @@ mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n,
                return false;
        return true;
 }
+#endif /* CONFIG_HAVE_CLK */
 
 static int
 mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
                  struct device *dev)
 {
-       const struct of_device_id *device;
-       struct device_node *np = dev->of_node;
-       u32 bus_freq, tclk;
-       int rc = 0;
-
        /* CLK is mandatory when using DT to describe the i2c bus. We
         * need to know tclk in order to calculate bus clock
         * factors.
@@ -744,6 +741,11 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
        /* Have OF but no CLK */
        return -ENODEV;
 #else
+       const struct of_device_id *device;
+       struct device_node *np = dev->of_node;
+       u32 bus_freq, tclk;
+       int rc = 0;
+
        if (IS_ERR(drv_data->clk)) {
                rc = -ENODEV;
                goto out;
index f4a01675fa71b4a18ac2b35714425be363442528..b7c857774708d369931abb733b9675500b9138bd 100644 (file)
@@ -780,12 +780,13 @@ static struct platform_driver mxs_i2c_driver = {
                   .owner = THIS_MODULE,
                   .of_match_table = mxs_i2c_dt_ids,
                   },
+       .probe = mxs_i2c_probe,
        .remove = mxs_i2c_remove,
 };
 
 static int __init mxs_i2c_init(void)
 {
-       return platform_driver_probe(&mxs_i2c_driver, mxs_i2c_probe);
+       return platform_driver_register(&mxs_i2c_driver);
 }
 subsys_initcall(mxs_i2c_init);
 
index 6d8308d5dc4e915c4584e2d5d9b3e5690882a2b9..9967a6f9c2ffba2fe4521a8abf19b49e978110a4 100644 (file)
@@ -939,6 +939,9 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
                /*
                 * ProDB0017052: Clear ARDY bit twice
                 */
+               if (stat & OMAP_I2C_STAT_ARDY)
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ARDY);
+
                if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
                                        OMAP_I2C_STAT_AL)) {
                        omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY |
index 3535f3c0f7b43233b09123c89b4727fc302cba3b..3747b9bf67d6440f684bcff945a2a85b93f6fe6c 100644 (file)
@@ -1178,8 +1178,6 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
 
        i2c_del_adapter(&i2c->adap);
 
-       clk_disable_unprepare(i2c->clk);
-
        if (pdev->dev.of_node && IS_ERR(i2c->pctrl))
                s3c24xx_i2c_dt_gpio_free(i2c);
 
index f8f6f2e552db29e344b41f4e42d0cbc1ac9fc000..04a17b9b38bbbb9f54cd8cb91ce2888aac95a478 100644 (file)
@@ -859,8 +859,7 @@ static const struct i2c_algorithm stu300_algo = {
        .functionality  = stu300_func,
 };
 
-static int __init
-stu300_probe(struct platform_device *pdev)
+static int stu300_probe(struct platform_device *pdev)
 {
        struct stu300_dev *dev;
        struct i2c_adapter *adap;
@@ -966,8 +965,7 @@ static SIMPLE_DEV_PM_OPS(stu300_pm, stu300_suspend, stu300_resume);
 #define STU300_I2C_PM  NULL
 #endif
 
-static int __exit
-stu300_remove(struct platform_device *pdev)
+static int stu300_remove(struct platform_device *pdev)
 {
        struct stu300_dev *dev = platform_get_drvdata(pdev);
 
@@ -989,13 +987,14 @@ static struct platform_driver stu300_i2c_driver = {
                .pm     = STU300_I2C_PM,
                .of_match_table = stu300_dt_match,
        },
-       .remove         = __exit_p(stu300_remove),
+       .probe = stu300_probe,
+       .remove = stu300_remove,
 
 };
 
 static int __init stu300_init(void)
 {
-       return platform_driver_probe(&stu300_i2c_driver, stu300_probe);
+       return platform_driver_register(&stu300_i2c_driver);
 }
 
 static void __exit stu300_exit(void)
index 29d3f045a2bfbc688beeb79f888cb72d10c3bcd2..3be58f89ac774962db749fcdea5c032e28edce0d 100644 (file)
@@ -1134,6 +1134,9 @@ static void acpi_i2c_register_devices(struct i2c_adapter *adap)
        acpi_handle handle;
        acpi_status status;
 
+       if (!adap->dev.parent)
+               return;
+
        handle = ACPI_HANDLE(adap->dev.parent);
        if (!handle)
                return;
index 74b41ae690f3e6dab7271319ed62c436ac30935a..928656e241ddc0873613dd7a5b786be4f0e5250e 100644 (file)
@@ -200,7 +200,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
        arb->parent = of_find_i2c_adapter_by_node(parent_np);
        if (!arb->parent) {
                dev_err(dev, "Cannot find parent bus\n");
-               return -EINVAL;
+               return -EPROBE_DEFER;
        }
 
        /* Actually add the mux adapter */
index 5d4a99ba743e39b21a9483ce2a15aabb41a84934..a764da777f08027da102e244556f9bb424b59494 100644 (file)
@@ -66,7 +66,7 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
        struct device_node *adapter_np, *child;
        struct i2c_adapter *adapter;
        unsigned *values, *gpios;
-       int i = 0;
+       int i = 0, ret;
 
        if (!np)
                return -ENODEV;
@@ -79,7 +79,7 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
        adapter = of_find_i2c_adapter_by_node(adapter_np);
        if (!adapter) {
                dev_err(&pdev->dev, "Cannot find parent bus\n");
-               return -ENODEV;
+               return -EPROBE_DEFER;
        }
        mux->data.parent = i2c_adapter_id(adapter);
        put_device(&adapter->dev);
@@ -116,8 +116,12 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
                return -ENOMEM;
        }
 
-       for (i = 0; i < mux->data.n_gpios; i++)
-               gpios[i] = of_get_named_gpio(np, "mux-gpios", i);
+       for (i = 0; i < mux->data.n_gpios; i++) {
+               ret = of_get_named_gpio(np, "mux-gpios", i);
+               if (ret < 0)
+                       return ret;
+               gpios[i] = ret;
+       }
 
        mux->data.gpios = gpios;
 
@@ -177,7 +181,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
        if (!parent) {
                dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
                        mux->data.parent);
-               return -ENODEV;
+               return -EPROBE_DEFER;
        }
 
        mux->parent = parent;
index 69a91732ae6561560ca6286007a10602e0e09ba4..68a37157377df12797b1b122ca4568d121559112 100644 (file)
@@ -113,7 +113,7 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
        adapter = of_find_i2c_adapter_by_node(adapter_np);
        if (!adapter) {
                dev_err(mux->dev, "Cannot find parent bus\n");
-               return -ENODEV;
+               return -EPROBE_DEFER;
        }
        mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
        put_device(&adapter->dev);
@@ -211,7 +211,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
        if (!mux->parent) {
                dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
                        mux->pdata->parent_bus_num);
-               ret = -ENODEV;
+               ret = -EPROBE_DEFER;
                goto err;
        }
 
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 12e32e6b41037c334c1eb8b3cef0e70145f8d228..81e3dc260993124981d45cacb9e472e9221d7b8a 100644 (file)
@@ -620,7 +620,7 @@ static int bma180_remove(struct i2c_client *client)
 #ifdef CONFIG_PM_SLEEP
 static int bma180_suspend(struct device *dev)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
        struct bma180_data *data = iio_priv(indio_dev);
        int ret;
 
@@ -633,7 +633,7 @@ static int bma180_suspend(struct device *dev)
 
 static int bma180_resume(struct device *dev)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
        struct bma180_data *data = iio_priv(indio_dev);
        int ret;
 
index 84be63bdf0382b6b44dfa14ff818e72377baf779..0f16b553e063f602e4e83104382827bb55cc72b2 100644 (file)
@@ -556,7 +556,7 @@ static const struct iio_info at91_adc_info = {
 
 static int at91_adc_probe(struct platform_device *pdev)
 {
-       unsigned int prsc, mstrclk, ticks, adc_clk, shtim;
+       unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
        int ret;
        struct iio_dev *idev;
        struct at91_adc_state *st;
@@ -649,6 +649,7 @@ static int at91_adc_probe(struct platform_device *pdev)
         */
        mstrclk = clk_get_rate(st->clk);
        adc_clk = clk_get_rate(st->adc_clk);
+       adc_clk_khz = adc_clk / 1000;
        prsc = (mstrclk / (2 * adc_clk)) - 1;
 
        if (!st->startup_time) {
@@ -662,15 +663,15 @@ static int at91_adc_probe(struct platform_device *pdev)
         * defined in the electrical characteristics of the board, divided by 8.
         * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
         */
-       ticks = round_up((st->startup_time * adc_clk /
-                         1000000) - 1, 8) / 8;
+       ticks = round_up((st->startup_time * adc_clk_khz /
+                         1000) - 1, 8) / 8;
        /*
         * a minimal Sample and Hold Time is necessary for the ADC to guarantee
         * the best converted final value between two channels selection
         * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock
         */
-       shtim = round_up((st->sample_hold_time * adc_clk /
-                         1000000) - 1, 1);
+       shtim = round_up((st->sample_hold_time * adc_clk_khz /
+                         1000) - 1, 1);
 
        reg = AT91_ADC_PRESCAL_(prsc) & st->registers->mr_prescal_mask;
        reg |= AT91_ADC_STARTUP_(ticks) & st->registers->mr_startup_mask;
index d0a79a4bce1c8f5d83410392e3343d779b015e2a..ba6f6a91dfffc63459ca9e92299832e946f740e3 100644 (file)
@@ -185,10 +185,8 @@ static int ad8366_remove(struct spi_device *spi)
 
        iio_device_unregister(indio_dev);
 
-       if (!IS_ERR(reg)) {
+       if (!IS_ERR(reg))
                regulator_disable(reg);
-               regulator_put(reg);
-       }
 
        return 0;
 }
index 9d19ba74f22bd92125501e2827ef51bbae59da13..415f3c6efd7293087cc1d5fa9313e9de308e6245 100644 (file)
@@ -41,6 +41,8 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
                goto error_ret;
        }
 
+       iio_buffer_init(&cb_buff->buffer);
+
        cb_buff->private = private;
        cb_buff->cb = cb;
        cb_buff->buffer.access = &iio_cb_access;
index 1f4a48e6a82c33f29b8985ad556698f0630e21af..1397b6e0e414c25835aebd829dc2bede15dedee3 100644 (file)
@@ -37,21 +37,21 @@ struct mcp4725_data {
 
 static int mcp4725_suspend(struct device *dev)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct mcp4725_data *data = iio_priv(indio_dev);
+       struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
+               to_i2c_client(dev)));
        u8 outbuf[2];
 
        outbuf[0] = (data->powerdown_mode + 1) << 4;
        outbuf[1] = 0;
        data->powerdown = true;
 
-       return i2c_master_send(to_i2c_client(dev), outbuf, 2);
+       return i2c_master_send(data->client, outbuf, 2);
 }
 
 static int mcp4725_resume(struct device *dev)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct mcp4725_data *data = iio_priv(indio_dev);
+       struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
+               to_i2c_client(dev)));
        u8 outbuf[2];
 
        /* restore previous DAC value */
@@ -59,7 +59,7 @@ static int mcp4725_resume(struct device *dev)
        outbuf[1] = data->dac_value & 0xff;
        data->powerdown = false;
 
-       return i2c_master_send(to_i2c_client(dev), outbuf, 2);
+       return i2c_master_send(data->client, outbuf, 2);
 }
 
 #ifdef CONFIG_PM_SLEEP
index a7b30be86ae06cb7ae59a077aa45ee4e58f52051..52605c0ea3a69fce7c1d312d4fa1610de43174fd 100644 (file)
@@ -525,8 +525,10 @@ static int adf4350_probe(struct spi_device *spi)
        }
 
        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
-       if (indio_dev == NULL)
-               return -ENOMEM;
+       if (indio_dev == NULL) {
+               ret =  -ENOMEM;
+               goto error_disable_clk;
+       }
 
        st = iio_priv(indio_dev);
 
index 05c1b74502a37265c86a23edaf97d4e602ead575..9b32253b824be454bf2f6c46bf02acb022b3be46 100644 (file)
@@ -49,11 +49,15 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
 #define iio_buffer_poll_addr (&iio_buffer_poll)
 #define iio_buffer_read_first_n_outer_addr (&iio_buffer_read_first_n_outer)
 
+void iio_disable_all_buffers(struct iio_dev *indio_dev);
+
 #else
 
 #define iio_buffer_poll_addr NULL
 #define iio_buffer_read_first_n_outer_addr NULL
 
+static inline void iio_disable_all_buffers(struct iio_dev *indio_dev) {}
+
 #endif
 
 int iio_device_register_eventset(struct iio_dev *indio_dev);
index e73033f3839a5e1eceba486cadf2825b30fb7027..2db7dcd826b9db6500e354498b385cbb3ebd9f7d 100644 (file)
@@ -460,6 +460,28 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
        return bytes;
 }
 
+void iio_disable_all_buffers(struct iio_dev *indio_dev)
+{
+       struct iio_buffer *buffer, *_buffer;
+
+       if (list_empty(&indio_dev->buffer_list))
+               return;
+
+       if (indio_dev->setup_ops->predisable)
+               indio_dev->setup_ops->predisable(indio_dev);
+
+       list_for_each_entry_safe(buffer, _buffer,
+                       &indio_dev->buffer_list, buffer_list)
+               list_del_init(&buffer->buffer_list);
+
+       indio_dev->currentmode = INDIO_DIRECT_MODE;
+       if (indio_dev->setup_ops->postdisable)
+               indio_dev->setup_ops->postdisable(indio_dev);
+
+       if (indio_dev->available_scan_masks == NULL)
+               kfree(indio_dev->active_scan_mask);
+}
+
 int iio_update_buffers(struct iio_dev *indio_dev,
                       struct iio_buffer *insert_buffer,
                       struct iio_buffer *remove_buffer)
@@ -528,8 +550,15 @@ int iio_update_buffers(struct iio_dev *indio_dev,
                         * Note can only occur when adding a buffer.
                         */
                        list_del(&insert_buffer->buffer_list);
-                       indio_dev->active_scan_mask = old_mask;
-                       success = -EINVAL;
+                       if (old_mask) {
+                               indio_dev->active_scan_mask = old_mask;
+                               success = -EINVAL;
+                       }
+                       else {
+                               kfree(compound_mask);
+                               ret = -EINVAL;
+                               goto error_ret;
+                       }
                }
        } else {
                indio_dev->active_scan_mask = compound_mask;
index 97f0297b120f41e7f73d9b5a5cf27887da146a92..f95c6979efd8f58fdf42e2a6d11a645b4191c17d 100644 (file)
@@ -848,13 +848,10 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
 static void iio_dev_release(struct device *device)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(device);
-       if (indio_dev->chrdev.dev)
-               cdev_del(&indio_dev->chrdev);
        if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
                iio_device_unregister_trigger_consumer(indio_dev);
        iio_device_unregister_eventset(indio_dev);
        iio_device_unregister_sysfs(indio_dev);
-       iio_device_unregister_debugfs(indio_dev);
 
        ida_simple_remove(&iio_ida, indio_dev->id);
        kfree(indio_dev);
@@ -970,6 +967,8 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp)
        if (test_and_set_bit(IIO_BUSY_BIT_POS, &indio_dev->flags))
                return -EBUSY;
 
+       iio_device_get(indio_dev);
+
        filp->private_data = indio_dev;
 
        return 0;
@@ -983,6 +982,8 @@ static int iio_chrdev_release(struct inode *inode, struct file *filp)
        struct iio_dev *indio_dev = container_of(inode->i_cdev,
                                                struct iio_dev, chrdev);
        clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags);
+       iio_device_put(indio_dev);
+
        return 0;
 }
 
@@ -1052,18 +1053,20 @@ int iio_device_register(struct iio_dev *indio_dev)
                indio_dev->setup_ops == NULL)
                indio_dev->setup_ops = &noop_ring_setup_ops;
 
-       ret = device_add(&indio_dev->dev);
-       if (ret < 0)
-               goto error_unreg_eventset;
        cdev_init(&indio_dev->chrdev, &iio_buffer_fileops);
        indio_dev->chrdev.owner = indio_dev->info->driver_module;
+       indio_dev->chrdev.kobj.parent = &indio_dev->dev.kobj;
        ret = cdev_add(&indio_dev->chrdev, indio_dev->dev.devt, 1);
        if (ret < 0)
-               goto error_del_device;
-       return 0;
+               goto error_unreg_eventset;
 
-error_del_device:
-       device_del(&indio_dev->dev);
+       ret = device_add(&indio_dev->dev);
+       if (ret < 0)
+               goto error_cdev_del;
+
+       return 0;
+error_cdev_del:
+       cdev_del(&indio_dev->chrdev);
 error_unreg_eventset:
        iio_device_unregister_eventset(indio_dev);
 error_free_sysfs:
@@ -1078,9 +1081,17 @@ EXPORT_SYMBOL(iio_device_register);
 void iio_device_unregister(struct iio_dev *indio_dev)
 {
        mutex_lock(&indio_dev->info_exist_lock);
+
+       device_del(&indio_dev->dev);
+
+       if (indio_dev->chrdev.dev)
+               cdev_del(&indio_dev->chrdev);
+       iio_device_unregister_debugfs(indio_dev);
+
+       iio_disable_all_buffers(indio_dev);
+
        indio_dev->info = NULL;
        mutex_unlock(&indio_dev->info_exist_lock);
-       device_del(&indio_dev->dev);
 }
 EXPORT_SYMBOL(iio_device_unregister);
 subsys_initcall(iio_init);
index 10aa9ef86cece1b80fa09c57d2a52e344e4dfc12..6be65ef5faa9b6e46716857af7ed67d8eb7ea004 100644 (file)
@@ -72,7 +72,8 @@ EXPORT_SYMBOL(iio_push_event);
 static unsigned int iio_event_poll(struct file *filep,
                             struct poll_table_struct *wait)
 {
-       struct iio_event_interface *ev_int = filep->private_data;
+       struct iio_dev *indio_dev = filep->private_data;
+       struct iio_event_interface *ev_int = indio_dev->event_interface;
        unsigned int events = 0;
 
        poll_wait(filep, &ev_int->wait, wait);
@@ -90,7 +91,8 @@ static ssize_t iio_event_chrdev_read(struct file *filep,
                                     size_t count,
                                     loff_t *f_ps)
 {
-       struct iio_event_interface *ev_int = filep->private_data;
+       struct iio_dev *indio_dev = filep->private_data;
+       struct iio_event_interface *ev_int = indio_dev->event_interface;
        unsigned int copied;
        int ret;
 
@@ -121,7 +123,8 @@ error_unlock:
 
 static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
 {
-       struct iio_event_interface *ev_int = filep->private_data;
+       struct iio_dev *indio_dev = filep->private_data;
+       struct iio_event_interface *ev_int = indio_dev->event_interface;
 
        spin_lock_irq(&ev_int->wait.lock);
        __clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
@@ -133,6 +136,8 @@ static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
        kfifo_reset_out(&ev_int->det_events);
        spin_unlock_irq(&ev_int->wait.lock);
 
+       iio_device_put(indio_dev);
+
        return 0;
 }
 
@@ -158,12 +163,15 @@ int iio_event_getfd(struct iio_dev *indio_dev)
                return -EBUSY;
        }
        spin_unlock_irq(&ev_int->wait.lock);
-       fd = anon_inode_getfd("iio:event",
-                               &iio_event_chrdev_fileops, ev_int, O_RDONLY);
+       iio_device_get(indio_dev);
+
+       fd = anon_inode_getfd("iio:event", &iio_event_chrdev_fileops,
+                               indio_dev, O_RDONLY);
        if (fd < 0) {
                spin_lock_irq(&ev_int->wait.lock);
                __clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
                spin_unlock_irq(&ev_int->wait.lock);
+               iio_device_put(indio_dev);
        }
        return fd;
 }
@@ -276,7 +284,7 @@ static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
                        goto error_ret;
                }
                if (chan->modified)
-                       mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel,
+                       mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel2,
                                                  i/IIO_EV_DIR_MAX,
                                                  i%IIO_EV_DIR_MAX);
                else if (chan->differential)
index e8d2849cc81d9110356691caaba587c80afff57e..cab3bc7494a2260214a85874310ac80deca87c0a 100644 (file)
@@ -29,9 +29,9 @@
 #define ST_MAGN_NUMBER_DATA_CHANNELS           3
 
 /* DEFAULT VALUE FOR SENSORS */
-#define ST_MAGN_DEFAULT_OUT_X_L_ADDR           0X04
-#define ST_MAGN_DEFAULT_OUT_Y_L_ADDR           0X08
-#define ST_MAGN_DEFAULT_OUT_Z_L_ADDR           0X06
+#define ST_MAGN_DEFAULT_OUT_X_H_ADDR           0X03
+#define ST_MAGN_DEFAULT_OUT_Y_H_ADDR           0X07
+#define ST_MAGN_DEFAULT_OUT_Z_H_ADDR           0X05
 
 /* FULLSCALE */
 #define ST_MAGN_FS_AVL_1300MG                  1300
 static const struct iio_chan_spec st_magn_16bit_channels[] = {
        ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
                        BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
-                       ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
-                       ST_MAGN_DEFAULT_OUT_X_L_ADDR),
+                       ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_BE, 16, 16,
+                       ST_MAGN_DEFAULT_OUT_X_H_ADDR),
        ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
                        BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
-                       ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
-                       ST_MAGN_DEFAULT_OUT_Y_L_ADDR),
+                       ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_BE, 16, 16,
+                       ST_MAGN_DEFAULT_OUT_Y_H_ADDR),
        ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
                        BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
-                       ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
-                       ST_MAGN_DEFAULT_OUT_Z_L_ADDR),
+                       ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_BE, 16, 16,
+                       ST_MAGN_DEFAULT_OUT_Z_H_ADDR),
        IIO_CHAN_SOFT_TIMESTAMP(3)
 };
 
index 64ccde3f1f7a60ae6693d1e91f117e370bd0141b..6d63883da1ab0e56be798538e1d965b1032eacb7 100644 (file)
@@ -255,12 +255,14 @@ static int tmp006_remove(struct i2c_client *client)
 #ifdef CONFIG_PM_SLEEP
 static int tmp006_suspend(struct device *dev)
 {
-       return tmp006_powerdown(iio_priv(dev_to_iio_dev(dev)));
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+       return tmp006_powerdown(iio_priv(indio_dev));
 }
 
 static int tmp006_resume(struct device *dev)
 {
-       struct tmp006_data *data = iio_priv(dev_to_iio_dev(dev));
+       struct tmp006_data *data = iio_priv(i2c_get_clientdata(
+               to_i2c_client(dev)));
        return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
                data->config | TMP006_CONFIG_MOD_MASK);
 }
index d5d1929753e4fdc95bbdc67625f5f0521ffeb32f..cedda25232be2454b3b2f0902152d96a7b1dfd75 100644 (file)
@@ -141,7 +141,7 @@ static const char *to_qp_state_str(int state)
                return "C2_QP_STATE_ERROR";
        default:
                return "<invalid QP state>";
-       };
+       }
 }
 
 void c2_ae_event(struct c2_dev *c2dev, u32 mq_index)
index 3f831de9a4d8a901607afc26c81827cc5c1e3bd5..b1a6cb3a2809282fbfab1b44b09c53e315a93466 100644 (file)
@@ -164,6 +164,7 @@ int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn)
 static int alloc_comp_eqs(struct mlx5_ib_dev *dev)
 {
        struct mlx5_eq_table *table = &dev->mdev.priv.eq_table;
+       char name[MLX5_MAX_EQ_NAME];
        struct mlx5_eq *eq, *n;
        int ncomp_vec;
        int nent;
@@ -180,11 +181,10 @@ static int alloc_comp_eqs(struct mlx5_ib_dev *dev)
                        goto clean;
                }
 
-               snprintf(eq->name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i);
+               snprintf(name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i);
                err = mlx5_create_map_eq(&dev->mdev, eq,
                                         i + MLX5_EQ_VEC_COMP_BASE, nent, 0,
-                                        eq->name,
-                                        &dev->mdev.priv.uuari.uars[0]);
+                                        name, &dev->mdev.priv.uuari.uars[0]);
                if (err) {
                        kfree(eq);
                        goto clean;
@@ -301,9 +301,8 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
        props->max_srq_sge         = max_rq_sg - 1;
        props->max_fast_reg_page_list_len = (unsigned int)-1;
        props->local_ca_ack_delay  = dev->mdev.caps.local_ca_ack_delay;
-       props->atomic_cap          = dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_ATOMIC ?
-               IB_ATOMIC_HCA : IB_ATOMIC_NONE;
-       props->masked_atomic_cap   = IB_ATOMIC_HCA;
+       props->atomic_cap          = IB_ATOMIC_NONE;
+       props->masked_atomic_cap   = IB_ATOMIC_NONE;
        props->max_pkeys           = be16_to_cpup((__be16 *)(out_mad->data + 28));
        props->max_mcast_grp       = 1 << dev->mdev.caps.log_max_mcg;
        props->max_mcast_qp_attach = dev->mdev.caps.max_qp_mcg;
@@ -1006,6 +1005,11 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
        ibev.device           = &ibdev->ib_dev;
        ibev.element.port_num = port;
 
+       if (port < 1 || port > ibdev->num_ports) {
+               mlx5_ib_warn(ibdev, "warning: event on port %d\n", port);
+               return;
+       }
+
        if (ibdev->ib_active)
                ib_dispatch_event(&ibev);
 }
index bd41df95b6f0214deb445ab228be8d157373074f..3453580b1eb2cc45800b8ee697157a24cf269970 100644 (file)
@@ -42,6 +42,10 @@ enum {
        DEF_CACHE_SIZE  = 10,
 };
 
+enum {
+       MLX5_UMR_ALIGN  = 2048
+};
+
 static __be64 *mr_align(__be64 *ptr, int align)
 {
        unsigned long mask = align - 1;
@@ -61,13 +65,11 @@ static int order2idx(struct mlx5_ib_dev *dev, int order)
 
 static int add_keys(struct mlx5_ib_dev *dev, int c, int num)
 {
-       struct device *ddev = dev->ib_dev.dma_device;
        struct mlx5_mr_cache *cache = &dev->cache;
        struct mlx5_cache_ent *ent = &cache->ent[c];
        struct mlx5_create_mkey_mbox_in *in;
        struct mlx5_ib_mr *mr;
        int npages = 1 << ent->order;
-       int size = sizeof(u64) * npages;
        int err = 0;
        int i;
 
@@ -83,21 +85,6 @@ static int add_keys(struct mlx5_ib_dev *dev, int c, int num)
                }
                mr->order = ent->order;
                mr->umred = 1;
-               mr->pas = kmalloc(size + 0x3f, GFP_KERNEL);
-               if (!mr->pas) {
-                       kfree(mr);
-                       err = -ENOMEM;
-                       goto out;
-               }
-               mr->dma = dma_map_single(ddev, mr_align(mr->pas, 0x40), size,
-                                        DMA_TO_DEVICE);
-               if (dma_mapping_error(ddev, mr->dma)) {
-                       kfree(mr->pas);
-                       kfree(mr);
-                       err = -ENOMEM;
-                       goto out;
-               }
-
                in->seg.status = 1 << 6;
                in->seg.xlt_oct_size = cpu_to_be32((npages + 1) / 2);
                in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
@@ -108,8 +95,6 @@ static int add_keys(struct mlx5_ib_dev *dev, int c, int num)
                                            sizeof(*in));
                if (err) {
                        mlx5_ib_warn(dev, "create mkey failed %d\n", err);
-                       dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
-                       kfree(mr->pas);
                        kfree(mr);
                        goto out;
                }
@@ -129,11 +114,9 @@ out:
 
 static void remove_keys(struct mlx5_ib_dev *dev, int c, int num)
 {
-       struct device *ddev = dev->ib_dev.dma_device;
        struct mlx5_mr_cache *cache = &dev->cache;
        struct mlx5_cache_ent *ent = &cache->ent[c];
        struct mlx5_ib_mr *mr;
-       int size;
        int err;
        int i;
 
@@ -149,14 +132,10 @@ static void remove_keys(struct mlx5_ib_dev *dev, int c, int num)
                ent->size--;
                spin_unlock(&ent->lock);
                err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr);
-               if (err) {
+               if (err)
                        mlx5_ib_warn(dev, "failed destroy mkey\n");
-               } else {
-                       size = ALIGN(sizeof(u64) * (1 << mr->order), 0x40);
-                       dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
-                       kfree(mr->pas);
+               else
                        kfree(mr);
-               }
        }
 }
 
@@ -408,13 +387,12 @@ static void free_cached_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
 
 static void clean_keys(struct mlx5_ib_dev *dev, int c)
 {
-       struct device *ddev = dev->ib_dev.dma_device;
        struct mlx5_mr_cache *cache = &dev->cache;
        struct mlx5_cache_ent *ent = &cache->ent[c];
        struct mlx5_ib_mr *mr;
-       int size;
        int err;
 
+       cancel_delayed_work(&ent->dwork);
        while (1) {
                spin_lock(&ent->lock);
                if (list_empty(&ent->head)) {
@@ -427,14 +405,10 @@ static void clean_keys(struct mlx5_ib_dev *dev, int c)
                ent->size--;
                spin_unlock(&ent->lock);
                err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr);
-               if (err) {
+               if (err)
                        mlx5_ib_warn(dev, "failed destroy mkey\n");
-               } else {
-                       size = ALIGN(sizeof(u64) * (1 << mr->order), 0x40);
-                       dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
-                       kfree(mr->pas);
+               else
                        kfree(mr);
-               }
        }
 }
 
@@ -540,13 +514,15 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev)
        int i;
 
        dev->cache.stopped = 1;
-       destroy_workqueue(dev->cache.wq);
+       flush_workqueue(dev->cache.wq);
 
        mlx5_mr_cache_debugfs_cleanup(dev);
 
        for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++)
                clean_keys(dev, i);
 
+       destroy_workqueue(dev->cache.wq);
+
        return 0;
 }
 
@@ -675,10 +651,12 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
                                  int page_shift, int order, int access_flags)
 {
        struct mlx5_ib_dev *dev = to_mdev(pd->device);
+       struct device *ddev = dev->ib_dev.dma_device;
        struct umr_common *umrc = &dev->umrc;
        struct ib_send_wr wr, *bad;
        struct mlx5_ib_mr *mr;
        struct ib_sge sg;
+       int size = sizeof(u64) * npages;
        int err;
        int i;
 
@@ -697,7 +675,22 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
        if (!mr)
                return ERR_PTR(-EAGAIN);
 
-       mlx5_ib_populate_pas(dev, umem, page_shift, mr_align(mr->pas, 0x40), 1);
+       mr->pas = kmalloc(size + MLX5_UMR_ALIGN - 1, GFP_KERNEL);
+       if (!mr->pas) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       mlx5_ib_populate_pas(dev, umem, page_shift,
+                            mr_align(mr->pas, MLX5_UMR_ALIGN), 1);
+
+       mr->dma = dma_map_single(ddev, mr_align(mr->pas, MLX5_UMR_ALIGN), size,
+                                DMA_TO_DEVICE);
+       if (dma_mapping_error(ddev, mr->dma)) {
+               kfree(mr->pas);
+               err = -ENOMEM;
+               goto error;
+       }
 
        memset(&wr, 0, sizeof(wr));
        wr.wr_id = (u64)(unsigned long)mr;
@@ -718,6 +711,9 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
        wait_for_completion(&mr->done);
        up(&umrc->sem);
 
+       dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
+       kfree(mr->pas);
+
        if (mr->status != IB_WC_SUCCESS) {
                mlx5_ib_warn(dev, "reg umr failed\n");
                err = -EFAULT;
index 045f8cdbd303deba81e60c5f1f52330b536b9617..5659ea88074108e60d9253085ce89f962326b808 100644 (file)
@@ -203,7 +203,7 @@ static int sq_overhead(enum ib_qp_type qp_type)
 
        switch (qp_type) {
        case IB_QPT_XRC_INI:
-               size = sizeof(struct mlx5_wqe_xrc_seg);
+               size += sizeof(struct mlx5_wqe_xrc_seg);
                /* fall through */
        case IB_QPT_RC:
                size += sizeof(struct mlx5_wqe_ctrl_seg) +
@@ -211,20 +211,23 @@ static int sq_overhead(enum ib_qp_type qp_type)
                        sizeof(struct mlx5_wqe_raddr_seg);
                break;
 
+       case IB_QPT_XRC_TGT:
+               return 0;
+
        case IB_QPT_UC:
-               size = sizeof(struct mlx5_wqe_ctrl_seg) +
+               size += sizeof(struct mlx5_wqe_ctrl_seg) +
                        sizeof(struct mlx5_wqe_raddr_seg);
                break;
 
        case IB_QPT_UD:
        case IB_QPT_SMI:
        case IB_QPT_GSI:
-               size = sizeof(struct mlx5_wqe_ctrl_seg) +
+               size += sizeof(struct mlx5_wqe_ctrl_seg) +
                        sizeof(struct mlx5_wqe_datagram_seg);
                break;
 
        case MLX5_IB_QPT_REG_UMR:
-               size = sizeof(struct mlx5_wqe_ctrl_seg) +
+               size += sizeof(struct mlx5_wqe_ctrl_seg) +
                        sizeof(struct mlx5_wqe_umr_ctrl_seg) +
                        sizeof(struct mlx5_mkey_seg);
                break;
@@ -270,7 +273,8 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
                return wqe_size;
 
        if (wqe_size > dev->mdev.caps.max_sq_desc_sz) {
-               mlx5_ib_dbg(dev, "\n");
+               mlx5_ib_dbg(dev, "wqe_size(%d) > max_sq_desc_sz(%d)\n",
+                           wqe_size, dev->mdev.caps.max_sq_desc_sz);
                return -EINVAL;
        }
 
@@ -280,9 +284,15 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
 
        wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size);
        qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB;
+       if (qp->sq.wqe_cnt > dev->mdev.caps.max_wqes) {
+               mlx5_ib_dbg(dev, "wqe count(%d) exceeds limits(%d)\n",
+                           qp->sq.wqe_cnt, dev->mdev.caps.max_wqes);
+               return -ENOMEM;
+       }
        qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB);
        qp->sq.max_gs = attr->cap.max_send_sge;
-       qp->sq.max_post = 1 << ilog2(wq_size / wqe_size);
+       qp->sq.max_post = wq_size / wqe_size;
+       attr->cap.max_send_wr = qp->sq.max_post;
 
        return wq_size;
 }
@@ -1280,6 +1290,11 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q
                                          MLX5_QP_OPTPAR_Q_KEY,
                        [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_PKEY_INDEX    |
                                           MLX5_QP_OPTPAR_Q_KEY,
+                       [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH |
+                                         MLX5_QP_OPTPAR_RRE            |
+                                         MLX5_QP_OPTPAR_RAE            |
+                                         MLX5_QP_OPTPAR_RWE            |
+                                         MLX5_QP_OPTPAR_PKEY_INDEX,
                },
        },
        [MLX5_QP_STATE_RTR] = {
@@ -1314,6 +1329,11 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q
                [MLX5_QP_STATE_RTS] = {
                        [MLX5_QP_ST_UD]  = MLX5_QP_OPTPAR_Q_KEY,
                        [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_Q_KEY,
+                       [MLX5_QP_ST_UC]  = MLX5_QP_OPTPAR_RWE,
+                       [MLX5_QP_ST_RC]  = MLX5_QP_OPTPAR_RNR_TIMEOUT   |
+                                          MLX5_QP_OPTPAR_RWE           |
+                                          MLX5_QP_OPTPAR_RAE           |
+                                          MLX5_QP_OPTPAR_RRE,
                },
        },
 };
@@ -1651,29 +1671,6 @@ static __always_inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg,
        rseg->reserved = 0;
 }
 
-static void set_atomic_seg(struct mlx5_wqe_atomic_seg *aseg, struct ib_send_wr *wr)
-{
-       if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-               aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
-               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add);
-       } else if (wr->opcode == IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) {
-               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
-               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add_mask);
-       } else {
-               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
-               aseg->compare  = 0;
-       }
-}
-
-static void set_masked_atomic_seg(struct mlx5_wqe_masked_atomic_seg *aseg,
-                                 struct ib_send_wr *wr)
-{
-       aseg->swap_add          = cpu_to_be64(wr->wr.atomic.swap);
-       aseg->swap_add_mask     = cpu_to_be64(wr->wr.atomic.swap_mask);
-       aseg->compare           = cpu_to_be64(wr->wr.atomic.compare_add);
-       aseg->compare_mask      = cpu_to_be64(wr->wr.atomic.compare_add_mask);
-}
-
 static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg,
                             struct ib_send_wr *wr)
 {
@@ -2063,28 +2060,11 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 
                        case IB_WR_ATOMIC_CMP_AND_SWP:
                        case IB_WR_ATOMIC_FETCH_AND_ADD:
-                               set_raddr_seg(seg, wr->wr.atomic.remote_addr,
-                                             wr->wr.atomic.rkey);
-                               seg  += sizeof(struct mlx5_wqe_raddr_seg);
-
-                               set_atomic_seg(seg, wr);
-                               seg  += sizeof(struct mlx5_wqe_atomic_seg);
-
-                               size += (sizeof(struct mlx5_wqe_raddr_seg) +
-                                        sizeof(struct mlx5_wqe_atomic_seg)) / 16;
-                               break;
-
                        case IB_WR_MASKED_ATOMIC_CMP_AND_SWP:
-                               set_raddr_seg(seg, wr->wr.atomic.remote_addr,
-                                             wr->wr.atomic.rkey);
-                               seg  += sizeof(struct mlx5_wqe_raddr_seg);
-
-                               set_masked_atomic_seg(seg, wr);
-                               seg  += sizeof(struct mlx5_wqe_masked_atomic_seg);
-
-                               size += (sizeof(struct mlx5_wqe_raddr_seg) +
-                                        sizeof(struct mlx5_wqe_masked_atomic_seg)) / 16;
-                               break;
+                               mlx5_ib_warn(dev, "Atomic operations are not supported yet\n");
+                               err = -ENOSYS;
+                               *bad_wr = wr;
+                               goto out;
 
                        case IB_WR_LOCAL_INV:
                                next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
index 84d297afd6a9889642007a4b3d6b2e0e6e25be74..0aa478bc291ae39aec0ed8c243cce72fe7ed2bdd 100644 (file)
@@ -295,7 +295,7 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
        mlx5_vfree(in);
        if (err) {
                mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err);
-               goto err_srq;
+               goto err_usr_kern_srq;
        }
 
        mlx5_ib_dbg(dev, "create SRQ with srqn 0x%x\n", srq->msrq.srqn);
@@ -316,6 +316,8 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
 
 err_core:
        mlx5_core_destroy_srq(&dev->mdev, &srq->msrq);
+
+err_usr_kern_srq:
        if (pd->uobject)
                destroy_srq_user(pd, srq);
        else
index 7c9d35f39d756950b9470d50201f882ca6fba1e3..69020173899397ee5889287ee79f0c3525ab8991 100644 (file)
@@ -357,7 +357,7 @@ static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)
                        mthca_warn(dev, "Unhandled event %02x(%02x) on EQ %d\n",
                                   eqe->type, eqe->subtype, eq->eqn);
                        break;
-               };
+               }
 
                set_eqe_hw(eqe);
                ++eq->cons_index;
index 4ed8235d2d36d818360cce7e2d43010e0840ab62..50219ab2279d56ae6599e7189b06034bf12049d9 100644 (file)
@@ -150,7 +150,7 @@ enum ib_qp_state get_ibqp_state(enum ocrdma_qp_state qps)
                return IB_QPS_SQE;
        case OCRDMA_QPS_ERR:
                return IB_QPS_ERR;
-       };
+       }
        return IB_QPS_ERR;
 }
 
@@ -171,7 +171,7 @@ static enum ocrdma_qp_state get_ocrdma_qp_state(enum ib_qp_state qps)
                return OCRDMA_QPS_SQE;
        case IB_QPS_ERR:
                return OCRDMA_QPS_ERR;
-       };
+       }
        return OCRDMA_QPS_ERR;
 }
 
@@ -1982,7 +1982,7 @@ int ocrdma_mbx_create_qp(struct ocrdma_qp *qp, struct ib_qp_init_attr *attrs,
                break;
        default:
                return -EINVAL;
-       };
+       }
 
        cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_QP, sizeof(*cmd));
        if (!cmd)
index 56e004940f1806c9203e788985395ea4ea5bdddb..0ce7674621eaba2aa310fef332695b67f3057971 100644 (file)
@@ -531,7 +531,7 @@ static void ocrdma_event_handler(struct ocrdma_dev *dev, u32 event)
        case BE_DEV_DOWN:
                ocrdma_close(dev);
                break;
-       };
+       }
 }
 
 static struct ocrdma_driver ocrdma_drv = {
index 6e982bb43c3172d2cc36b844c1b97f8bb0960237..69f1d1221a6bea07039fc37b5ead33f941fc74a4 100644 (file)
@@ -141,7 +141,7 @@ static inline void get_link_speed_and_width(struct ocrdma_dev *dev,
                /* Unsupported */
                *ib_speed = IB_SPEED_SDR;
                *ib_width = IB_WIDTH_1X;
-       };
+       }
 }
 
 
@@ -2331,7 +2331,7 @@ static enum ib_wc_status ocrdma_to_ibwc_err(u16 status)
        default:
                ibwc_status = IB_WC_GENERAL_ERR;
                break;
-       };
+       }
        return ibwc_status;
 }
 
@@ -2370,7 +2370,7 @@ static void ocrdma_update_wc(struct ocrdma_qp *qp, struct ib_wc *ibwc,
                pr_err("%s() invalid opcode received = 0x%x\n",
                       __func__, hdr->cw & OCRDMA_WQE_OPCODE_MASK);
                break;
-       };
+       }
 }
 
 static void ocrdma_set_cqe_status_flushed(struct ocrdma_qp *qp,
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 653ac6bfc57a61147bbeb72fbc598a0d1884b734..6c923c7039a156d10eeaa7a39f339ecd84a360ac 100644 (file)
@@ -1588,7 +1588,7 @@ static int srpt_build_tskmgmt_rsp(struct srpt_rdma_ch *ch,
        int resp_data_len;
        int resp_len;
 
-       resp_data_len = (rsp_code == SRP_TSK_MGMT_SUCCESS) ? 0 : 4;
+       resp_data_len = 4;
        resp_len = sizeof(*srp_rsp) + resp_data_len;
 
        srp_rsp = ioctx->ioctx.buf;
@@ -1600,11 +1600,9 @@ static int srpt_build_tskmgmt_rsp(struct srpt_rdma_ch *ch,
                                    + atomic_xchg(&ch->req_lim_delta, 0));
        srp_rsp->tag = tag;
 
-       if (rsp_code != SRP_TSK_MGMT_SUCCESS) {
-               srp_rsp->flags |= SRP_RSP_FLAG_RSPVALID;
-               srp_rsp->resp_data_len = cpu_to_be32(resp_data_len);
-               srp_rsp->data[3] = rsp_code;
-       }
+       srp_rsp->flags |= SRP_RSP_FLAG_RSPVALID;
+       srp_rsp->resp_data_len = cpu_to_be32(resp_data_len);
+       srp_rsp->data[3] = rsp_code;
 
        return resp_len;
 }
@@ -2358,6 +2356,8 @@ static void srpt_release_channel_work(struct work_struct *w)
        transport_deregister_session(se_sess);
        ch->sess = NULL;
 
+       ib_destroy_cm_id(ch->cm_id);
+
        srpt_destroy_ch_ib(ch);
 
        srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_ring,
@@ -2368,8 +2368,6 @@ static void srpt_release_channel_work(struct work_struct *w)
        list_del(&ch->list);
        spin_unlock_irq(&sdev->spinlock);
 
-       ib_destroy_cm_id(ch->cm_id);
-
        if (ch->release_done)
                complete(ch->release_done);
 
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 121cd63d3334b7a89b6a928fe62c8227b6f07231..005d852a06e99d6ebf2299cd6a23eb9023712ef8 100644 (file)
@@ -234,7 +234,7 @@ static int as5011_probe(struct i2c_client *client,
        int irq;
        int error;
 
-       plat_data = client->dev.platform_data;
+       plat_data = dev_get_platdata(&client->dev);
        if (!plat_data)
                return -EINVAL;
 
@@ -288,6 +288,7 @@ static int as5011_probe(struct i2c_client *client,
        if (irq < 0) {
                dev_err(&client->dev,
                        "Failed to get irq number for button gpio\n");
+               error = irq;
                goto err_free_button_gpio;
        }
 
index 59c10ec5a2a13310ef667c96d9cb8675f739368c..8aa6e4c497da77c70df1827934b696c2bc4c0159 100644 (file)
@@ -61,7 +61,7 @@ static void dc_pad_callback(struct mapleq *mq)
 
 static int dc_pad_open(struct input_dev *dev)
 {
-       struct dc_pad *pad = dev->dev.platform_data;
+       struct dc_pad *pad = dev_get_platdata(&dev->dev);
 
        maple_getcond_callback(pad->mdev, dc_pad_callback, HZ/20,
                MAPLE_FUNC_CONTROLLER);
@@ -71,7 +71,7 @@ static int dc_pad_open(struct input_dev *dev)
 
 static void dc_pad_close(struct input_dev *dev)
 {
-       struct dc_pad *pad = dev->dev.platform_data;
+       struct dc_pad *pad = dev_get_platdata(&dev->dev);
 
        maple_getcond_callback(pad->mdev, dc_pad_callback, 0,
                MAPLE_FUNC_CONTROLLER);
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 03c8cc5cb6c144433c2883f12ca8685ba4bc7c26..328cfc1eed95dac7d8452547a389909d0320e35a 100644 (file)
@@ -442,12 +442,6 @@ static int imx_keypad_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "no I/O memory defined in platform data\n");
-               return -EINVAL;
-       }
-
        input_dev = devm_input_allocate_device(&pdev->dev);
        if (!input_dev) {
                dev_err(&pdev->dev, "failed to allocate the input device\n");
@@ -468,6 +462,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
        setup_timer(&keypad->check_matrix_timer,
                    imx_keypad_check_for_events, (unsigned long) keypad);
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(keypad->mmio_base))
                return PTR_ERR(keypad->mmio_base);
index 7c7af2b01e6566fd6ca8781bc6bc0154c4f14426..bc2cdaf563fd76da86c9318f0159a9d7a492590f 100644 (file)
@@ -271,7 +271,7 @@ static int max7359_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int max7359_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
index 20d872d6f6031ec78dc4f226a4b02e991a90900f..b3e3edab6d9f208050bf029a85c0b63ab755969b 100644 (file)
@@ -171,12 +171,6 @@ static int nspire_keypad_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "missing platform resources\n");
-               return -EINVAL;
-       }
-
        keypad = devm_kzalloc(&pdev->dev, sizeof(struct nspire_keypad),
                              GFP_KERNEL);
        if (!keypad) {
@@ -208,6 +202,7 @@ static int nspire_keypad_probe(struct platform_device *pdev)
                return PTR_ERR(keypad->clk);
        }
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        keypad->reg_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(keypad->reg_base))
                return PTR_ERR(keypad->reg_base);
index f4aa53a1fd69bb70f0e680e95688e251f355f1e9..30acfd49fa6c16ffed7d759b834dea335afd1324 100644 (file)
 #define OMAP4_KBD_FULLCODE63_32                0x48
 
 /* OMAP4 bit definitions */
-#define OMAP4_DEF_IRQENABLE_EVENTEN    (1 << 0)
-#define OMAP4_DEF_IRQENABLE_LONGKEY    (1 << 1)
-#define OMAP4_DEF_IRQENABLE_TIMEOUTEN  (1 << 2)
-#define OMAP4_DEF_WUP_EVENT_ENA                (1 << 0)
-#define OMAP4_DEF_WUP_LONG_KEY_ENA     (1 << 1)
-#define OMAP4_DEF_CTRL_NOSOFTMODE      (1 << 1)
-#define OMAP4_DEF_CTRLPTVVALUE         (1 << 2)
-#define OMAP4_DEF_CTRLPTV              (1 << 1)
+#define OMAP4_DEF_IRQENABLE_EVENTEN    BIT(0)
+#define OMAP4_DEF_IRQENABLE_LONGKEY    BIT(1)
+#define OMAP4_DEF_WUP_EVENT_ENA                BIT(0)
+#define OMAP4_DEF_WUP_LONG_KEY_ENA     BIT(1)
+#define OMAP4_DEF_CTRL_NOSOFTMODE      BIT(1)
+#define OMAP4_DEF_CTRL_PTV_SHIFT       2
 
 /* OMAP4 values */
-#define OMAP4_VAL_IRQDISABLE           0x00
-#define OMAP4_VAL_DEBOUNCINGTIME       0x07
-#define OMAP4_VAL_FUNCTIONALCFG                0x1E
-
-#define OMAP4_MASK_IRQSTATUSDISABLE    0xFFFF
+#define OMAP4_VAL_IRQDISABLE           0x0
+#define OMAP4_VAL_DEBOUNCINGTIME       0x7
+#define OMAP4_VAL_PVT                  0x7
 
 enum {
        KBD_REVISION_OMAP4 = 0,
@@ -78,6 +74,7 @@ struct omap4_keypad {
        struct input_dev *input;
 
        void __iomem *base;
+       bool irq_wake_enabled;
        unsigned int irq;
 
        unsigned int rows;
@@ -116,8 +113,22 @@ static void kbd_write_irqreg(struct omap4_keypad *keypad_data,
 }
 
 
-/* Interrupt handler */
-static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
+/* Interrupt handlers */
+static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id)
+{
+       struct omap4_keypad *keypad_data = dev_id;
+
+       if (kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)) {
+               /* Disable interrupts */
+               kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
+                                OMAP4_VAL_IRQDISABLE);
+               return IRQ_WAKE_THREAD;
+       }
+
+       return IRQ_NONE;
+}
+
+static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id)
 {
        struct omap4_keypad *keypad_data = dev_id;
        struct input_dev *input_dev = keypad_data->input;
@@ -125,10 +136,6 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
        unsigned int col, row, code, changed;
        u32 *new_state = (u32 *) key_state;
 
-       /* Disable interrupts */
-       kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
-                        OMAP4_VAL_IRQDISABLE);
-
        *new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
        *(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);
 
@@ -175,11 +182,13 @@ static int omap4_keypad_open(struct input_dev *input)
        disable_irq(keypad_data->irq);
 
        kbd_writel(keypad_data, OMAP4_KBD_CTRL,
-                       OMAP4_VAL_FUNCTIONALCFG);
+                       OMAP4_DEF_CTRL_NOSOFTMODE |
+                       (OMAP4_VAL_PVT << OMAP4_DEF_CTRL_PTV_SHIFT));
        kbd_writel(keypad_data, OMAP4_KBD_DEBOUNCINGTIME,
                        OMAP4_VAL_DEBOUNCINGTIME);
+       /* clear pending interrupts */
        kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
-                       OMAP4_VAL_IRQDISABLE);
+                        kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
        kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
                        OMAP4_DEF_IRQENABLE_EVENTEN |
                                OMAP4_DEF_IRQENABLE_LONGKEY);
@@ -363,14 +372,15 @@ static int omap4_keypad_probe(struct platform_device *pdev)
                goto err_free_keymap;
        }
 
-       error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
-                            IRQF_TRIGGER_RISING,
-                            "omap4-keypad", keypad_data);
+       error = request_threaded_irq(keypad_data->irq, omap4_keypad_irq_handler,
+                                    omap4_keypad_irq_thread_fn, 0,
+                                    "omap4-keypad", keypad_data);
        if (error) {
                dev_err(&pdev->dev, "failed to register interrupt\n");
                goto err_free_input;
        }
 
+       device_init_wakeup(&pdev->dev, true);
        pm_runtime_put_sync(&pdev->dev);
 
        error = input_register_device(keypad_data->input);
@@ -384,6 +394,7 @@ static int omap4_keypad_probe(struct platform_device *pdev)
 
 err_pm_disable:
        pm_runtime_disable(&pdev->dev);
+       device_init_wakeup(&pdev->dev, false);
        free_irq(keypad_data->irq, keypad_data);
 err_free_keymap:
        kfree(keypad_data->keymap);
@@ -409,6 +420,8 @@ static int omap4_keypad_remove(struct platform_device *pdev)
 
        pm_runtime_disable(&pdev->dev);
 
+       device_init_wakeup(&pdev->dev, false);
+
        input_unregister_device(keypad_data->input);
 
        iounmap(keypad_data->base);
@@ -430,12 +443,46 @@ static const struct of_device_id omap_keypad_dt_match[] = {
 MODULE_DEVICE_TABLE(of, omap_keypad_dt_match);
 #endif
 
+#ifdef CONFIG_PM_SLEEP
+static int omap4_keypad_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
+       int error;
+
+       if (device_may_wakeup(&pdev->dev)) {
+               error = enable_irq_wake(keypad_data->irq);
+               if (!error)
+                       keypad_data->irq_wake_enabled = true;
+       }
+
+       return 0;
+}
+
+static int omap4_keypad_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
+
+       if (device_may_wakeup(&pdev->dev) && keypad_data->irq_wake_enabled) {
+               disable_irq_wake(keypad_data->irq);
+               keypad_data->irq_wake_enabled = false;
+       }
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(omap4_keypad_pm_ops,
+                        omap4_keypad_suspend, omap4_keypad_resume);
+
 static struct platform_driver omap4_keypad_driver = {
        .probe          = omap4_keypad_probe,
        .remove         = omap4_keypad_remove,
        .driver         = {
                .name   = "omap4-keypad",
                .owner  = THIS_MODULE,
+               .pm     = &omap4_keypad_pm_ops,
                .of_match_table = of_match_ptr(omap_keypad_dt_match),
        },
 };
index 42b773b3125a03702ed86350f12fbd685d5e2952..6c561ec3cc09853240ad1cc0f3bbc6902085ff95 100644 (file)
@@ -243,6 +243,32 @@ static int qt1070_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int qt1070_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct qt1070_data *data = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(data->irq);
+
+       return 0;
+}
+
+static int qt1070_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct qt1070_data *data = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(data->irq);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(qt1070_pm_ops, qt1070_suspend, qt1070_resume);
+
 static const struct i2c_device_id qt1070_id[] = {
        { "qt1070", 0 },
        { },
@@ -253,6 +279,7 @@ static struct i2c_driver qt1070_driver = {
        .driver = {
                .name   = "qt1070",
                .owner  = THIS_MODULE,
+               .pm     = &qt1070_pm_ops,
        },
        .id_table       = qt1070_id,
        .probe          = qt1070_probe,
index 7111124b53621de7c5de1df601f1d1fba6f8505f..85ff530d9a913c00741f39bf0082f701e4a59d91 100644 (file)
@@ -191,12 +191,6 @@ static int spear_kbd_probe(struct platform_device *pdev)
        int irq;
        int error;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "no keyboard resource defined\n");
-               return -EBUSY;
-       }
-
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                dev_err(&pdev->dev, "not able to get irq for the device\n");
@@ -228,6 +222,7 @@ static int spear_kbd_probe(struct platform_device *pdev)
                kbd->suspended_rate = pdata->suspended_rate;
        }
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        kbd->io_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(kbd->io_base))
                return PTR_ERR(kbd->io_base);
index b46142f78ef24fec15147c190880b01bffb458bd..9cd20e6905a08274bff3d55a48fa7e26d8f2b2c6 100644 (file)
@@ -638,12 +638,6 @@ static int tegra_kbc_probe(struct platform_device *pdev)
        if (!tegra_kbc_check_pin_cfg(kbc, &num_rows))
                return -EINVAL;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "failed to get I/O memory\n");
-               return -ENXIO;
-       }
-
        kbc->irq = platform_get_irq(pdev, 0);
        if (kbc->irq < 0) {
                dev_err(&pdev->dev, "failed to get keyboard IRQ\n");
@@ -658,6 +652,7 @@ static int tegra_kbc_probe(struct platform_device *pdev)
 
        setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc);
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        kbc->mmio = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(kbc->mmio))
                return PTR_ERR(kbc->mmio);
index 0b541cdf9b8e69f238c2f7fcd5eadebe644ec3e3..aa51baaa9b1ec273acc95c7edcb838ed81fe5fe2 100644 (file)
@@ -647,4 +647,14 @@ config INPUT_SIRFSOC_ONKEY
 
          If unsure, say N.
 
+config INPUT_IDEAPAD_SLIDEBAR
+       tristate "IdeaPad Laptop Slidebar"
+       depends on INPUT
+       depends on SERIO_I8042
+       help
+         Say Y here if you have an IdeaPad laptop with a slidebar.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ideapad_slidebar.
+
 endif
index 829de43a2427933b72bbef8e32ed5a4072ff8e4a..0ebfb6dbf0f7788afd75b7a88bd171ff90b567b6 100644 (file)
@@ -61,3 +61,4 @@ obj-$(CONFIG_INPUT_WISTRON_BTNS)      += wistron_btns.o
 obj-$(CONFIG_INPUT_WM831X_ON)          += wm831x-on.o
 obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)        += xen-kbdfront.o
 obj-$(CONFIG_INPUT_YEALINK)            += yealink.o
+obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR)   += ideapad_slidebar.o
diff --git a/drivers/input/misc/ideapad_slidebar.c b/drivers/input/misc/ideapad_slidebar.c
new file mode 100644 (file)
index 0000000..edfd623
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Input driver for slidebars on some Lenovo IdeaPad laptops
+ *
+ * Copyright (C) 2013 Andrey Moiseev <o2g.org.ru@gmail.com>
+ *
+ * Reverse-engineered from Lenovo SlideNav software (SBarHook.dll).
+ *
+ * This program is free software; 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.
+ *
+ * Trademarks are the property of their respective owners.
+ */
+
+/*
+ * Currently tested and works on:
+ *     Lenovo IdeaPad Y550
+ *     Lenovo IdeaPad Y550P
+ *
+ * Other models can be added easily. To test,
+ * load with 'force' parameter set 'true'.
+ *
+ * LEDs blinking and input mode are managed via sysfs,
+ * (hex, unsigned byte value):
+ * /sys/devices/platform/ideapad_slidebar/slidebar_mode
+ *
+ * The value is in byte range, however, I only figured out
+ * how bits 0b10011001 work. Some other bits, probably,
+ * are meaningfull too.
+ *
+ * Possible states:
+ *
+ * STD_INT, ONMOV_INT, OFF_INT, LAST_POLL, OFF_POLL
+ *
+ * Meaning:
+ *           released      touched
+ * STD       'heartbeat'   lights follow the finger
+ * ONMOV     no lights     lights follow the finger
+ * LAST      at last pos   lights follow the finger
+ * OFF       no lights     no lights
+ *
+ * INT       all input events are generated, interrupts are used
+ * POLL      no input events by default, to get them,
+ *          send 0b10000000 (read below)
+ *
+ * Commands: write
+ *
+ * All      |  0b01001 -> STD_INT
+ * possible |  0b10001 -> ONMOV_INT
+ * states   |  0b01000 -> OFF_INT
+ *
+ *                      |  0b0 -> LAST_POLL
+ * STD_INT or ONMOV_INT |
+ *                      |  0b1 -> STD_INT
+ *
+ *                      |  0b0 -> OFF_POLL
+ * OFF_INT or OFF_POLL  |
+ *                      |  0b1 -> OFF_INT
+ *
+ * Any state |   0b10000000 ->  if the slidebar has updated data,
+ *                             produce one input event (last position),
+ *                             switch to respective POLL mode
+ *                             (like 0x0), if not in POLL mode yet.
+ *
+ * Get current state: read
+ *
+ * masked by 0x11 read value means:
+ *
+ * 0x00   LAST
+ * 0x01   STD
+ * 0x10   OFF
+ * 0x11   ONMOV
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/dmi.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/i8042.h>
+#include <linux/serio.h>
+
+#define IDEAPAD_BASE   0xff29
+
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static DEFINE_SPINLOCK(io_lock);
+
+static struct input_dev *slidebar_input_dev;
+static struct platform_device *slidebar_platform_dev;
+
+static u8 slidebar_pos_get(void)
+{
+       u8 res;
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_lock, flags);
+       outb(0xf4, 0xff29);
+       outb(0xbf, 0xff2a);
+       res = inb(0xff2b);
+       spin_unlock_irqrestore(&io_lock, flags);
+
+       return res;
+}
+
+static u8 slidebar_mode_get(void)
+{
+       u8 res;
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_lock, flags);
+       outb(0xf7, 0xff29);
+       outb(0x8b, 0xff2a);
+       res = inb(0xff2b);
+       spin_unlock_irqrestore(&io_lock, flags);
+
+       return res;
+}
+
+static void slidebar_mode_set(u8 mode)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_lock, flags);
+       outb(0xf7, 0xff29);
+       outb(0x8b, 0xff2a);
+       outb(mode, 0xff2b);
+       spin_unlock_irqrestore(&io_lock, flags);
+}
+
+static bool slidebar_i8042_filter(unsigned char data, unsigned char str,
+                                 struct serio *port)
+{
+       static bool extended = false;
+
+       /* We are only interested in data coming form KBC port */
+       if (str & I8042_STR_AUXDATA)
+               return false;
+
+       /* Scancodes: e03b on move, e0bb on release. */
+       if (data == 0xe0) {
+               extended = true;
+               return true;
+       }
+
+       if (!extended)
+               return false;
+
+       extended = false;
+
+       if (likely((data & 0x7f) != 0x3b)) {
+               serio_interrupt(port, 0xe0, 0);
+               return false;
+       }
+
+       if (data & 0x80) {
+               input_report_key(slidebar_input_dev, BTN_TOUCH, 0);
+       } else {
+               input_report_key(slidebar_input_dev, BTN_TOUCH, 1);
+               input_report_abs(slidebar_input_dev, ABS_X, slidebar_pos_get());
+       }
+       input_sync(slidebar_input_dev);
+
+       return true;
+}
+
+static ssize_t show_slidebar_mode(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       return sprintf(buf, "%x\n", slidebar_mode_get());
+}
+
+static ssize_t store_slidebar_mode(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
+{
+       u8 mode;
+       int error;
+
+       error = kstrtou8(buf, 0, &mode);
+       if (error)
+               return error;
+
+       slidebar_mode_set(mode);
+
+       return count;
+}
+
+static DEVICE_ATTR(slidebar_mode, S_IWUSR | S_IRUGO,
+                  show_slidebar_mode, store_slidebar_mode);
+
+static struct attribute *ideapad_attrs[] = {
+       &dev_attr_slidebar_mode.attr,
+       NULL
+};
+
+static struct attribute_group ideapad_attr_group = {
+       .attrs = ideapad_attrs
+};
+
+static const struct attribute_group *ideapad_attr_groups[] = {
+       &ideapad_attr_group,
+       NULL
+};
+
+static int __init ideapad_probe(struct platform_device* pdev)
+{
+       int err;
+
+       if (!request_region(IDEAPAD_BASE, 3, "ideapad_slidebar")) {
+               dev_err(&pdev->dev, "IO ports are busy\n");
+               return -EBUSY;
+       }
+
+       slidebar_input_dev = input_allocate_device();
+       if (!slidebar_input_dev) {
+               dev_err(&pdev->dev, "Failed to allocate input device\n");
+               err = -ENOMEM;
+               goto err_release_ports;
+       }
+
+       slidebar_input_dev->name = "IdeaPad Slidebar";
+       slidebar_input_dev->id.bustype = BUS_HOST;
+       slidebar_input_dev->dev.parent = &pdev->dev;
+       input_set_capability(slidebar_input_dev, EV_KEY, BTN_TOUCH);
+       input_set_capability(slidebar_input_dev, EV_ABS, ABS_X);
+       input_set_abs_params(slidebar_input_dev, ABS_X, 0, 0xff, 0, 0);
+
+       err = i8042_install_filter(slidebar_i8042_filter);
+       if (err) {
+               dev_err(&pdev->dev,
+                       "Failed to install i8042 filter: %d\n", err);
+               goto err_free_dev;
+       }
+
+       err = input_register_device(slidebar_input_dev);
+       if (err) {
+               dev_err(&pdev->dev,
+                       "Failed to register input device: %d\n", err);
+               goto err_remove_filter;
+       }
+
+       return 0;
+
+err_remove_filter:
+       i8042_remove_filter(slidebar_i8042_filter);
+err_free_dev:
+       input_free_device(slidebar_input_dev);
+err_release_ports:
+       release_region(IDEAPAD_BASE, 3);
+       return err;
+}
+
+static int ideapad_remove(struct platform_device *pdev)
+{
+       i8042_remove_filter(slidebar_i8042_filter);
+       input_unregister_device(slidebar_input_dev);
+       release_region(IDEAPAD_BASE, 3);
+
+       return 0;
+}
+
+static struct platform_driver slidebar_drv = {
+       .driver = {
+               .name = "ideapad_slidebar",
+               .owner = THIS_MODULE,
+       },
+       .remove = ideapad_remove,
+};
+
+static int __init ideapad_dmi_check(const struct dmi_system_id *id)
+{
+       pr_info("Laptop model '%s'\n", id->ident);
+       return 1;
+}
+
+static const struct dmi_system_id ideapad_dmi[] __initconst = {
+       {
+               .ident = "Lenovo IdeaPad Y550",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "20017"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Y550")
+               },
+               .callback = ideapad_dmi_check
+       },
+       {
+               .ident = "Lenovo IdeaPad Y550P",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "20035"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Y550P")
+               },
+               .callback = ideapad_dmi_check
+       },
+       { NULL, }
+};
+MODULE_DEVICE_TABLE(dmi, ideapad_dmi);
+
+static int __init slidebar_init(void)
+{
+       int err;
+
+       if (!force && !dmi_check_system(ideapad_dmi)) {
+               pr_err("DMI does not match\n");
+               return -ENODEV;
+       }
+
+       slidebar_platform_dev = platform_device_alloc("ideapad_slidebar", -1);
+       if (!slidebar_platform_dev) {
+               pr_err("Not enough memory\n");
+               return -ENOMEM;
+       }
+
+       slidebar_platform_dev->dev.groups = ideapad_attr_groups;
+
+       err = platform_device_add(slidebar_platform_dev);
+       if (err) {
+               pr_err("Failed to register platform device\n");
+               goto err_free_dev;
+       }
+
+       err = platform_driver_probe(&slidebar_drv, ideapad_probe);
+       if (err) {
+               pr_err("Failed to register platform driver\n");
+               goto err_delete_dev;
+       }
+
+       return 0;
+
+err_delete_dev:
+       platform_device_del(slidebar_platform_dev);
+err_free_dev:
+       platform_device_put(slidebar_platform_dev);
+       return err;
+}
+
+static void __exit slidebar_exit(void)
+{
+       platform_device_unregister(slidebar_platform_dev);
+       platform_driver_unregister(&slidebar_drv);
+}
+
+module_init(slidebar_init);
+module_exit(slidebar_exit);
+
+MODULE_AUTHOR("Andrey Moiseev <o2g.org.ru@gmail.com>");
+MODULE_DESCRIPTION("Slidebar input support for some Lenovo IdeaPad laptops");
+MODULE_LICENSE("GPL");
index a37f0c909aba7ad34ce95eaa9c23f3bdedd96b4b..2ff4d1c78ab8ff91c4338c6e40d6ff91fac349c3 100644 (file)
@@ -143,7 +143,7 @@ static int pwm_beeper_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int pwm_beeper_suspend(struct device *dev)
 {
        struct pwm_beeper *beeper = dev_get_drvdata(dev);
index 0c2dfc8e96918c3e022aad1920ece05e1115abd8..7864b0c3ebb3f2f2ad571cb04ac29b67572aaa85 100644 (file)
@@ -257,7 +257,6 @@ static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);
 
 static int twl6040_vibra_probe(struct platform_device *pdev)
 {
-       struct twl6040_vibra_data *pdata = pdev->dev.platform_data;
        struct device *twl6040_core_dev = pdev->dev.parent;
        struct device_node *twl6040_core_node = NULL;
        struct vibra_info *info;
@@ -270,8 +269,8 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
                                                 "vibra");
 #endif
 
-       if (!pdata && !twl6040_core_node) {
-               dev_err(&pdev->dev, "platform_data not available\n");
+       if (!twl6040_core_node) {
+               dev_err(&pdev->dev, "parent of node is missing?\n");
                return -EINVAL;
        }
 
@@ -284,27 +283,17 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
        info->dev = &pdev->dev;
 
        info->twl6040 = dev_get_drvdata(pdev->dev.parent);
-       if (pdata) {
-               info->vibldrv_res = pdata->vibldrv_res;
-               info->vibrdrv_res = pdata->vibrdrv_res;
-               info->viblmotor_res = pdata->viblmotor_res;
-               info->vibrmotor_res = pdata->vibrmotor_res;
-               vddvibl_uV = pdata->vddvibl_uV;
-               vddvibr_uV = pdata->vddvibr_uV;
-       } else {
-               of_property_read_u32(twl6040_core_node, "ti,vibldrv-res",
-                                    &info->vibldrv_res);
-               of_property_read_u32(twl6040_core_node, "ti,vibrdrv-res",
-                                    &info->vibrdrv_res);
-               of_property_read_u32(twl6040_core_node, "ti,viblmotor-res",
-                                    &info->viblmotor_res);
-               of_property_read_u32(twl6040_core_node, "ti,vibrmotor-res",
-                                    &info->vibrmotor_res);
-               of_property_read_u32(twl6040_core_node, "ti,vddvibl-uV",
-                                    &vddvibl_uV);
-               of_property_read_u32(twl6040_core_node, "ti,vddvibr-uV",
-                                    &vddvibr_uV);
-       }
+
+       of_property_read_u32(twl6040_core_node, "ti,vibldrv-res",
+                            &info->vibldrv_res);
+       of_property_read_u32(twl6040_core_node, "ti,vibrdrv-res",
+                            &info->vibrdrv_res);
+       of_property_read_u32(twl6040_core_node, "ti,viblmotor-res",
+                            &info->viblmotor_res);
+       of_property_read_u32(twl6040_core_node, "ti,vibrmotor-res",
+                            &info->vibrmotor_res);
+       of_property_read_u32(twl6040_core_node, "ti,vddvibl-uV", &vddvibl_uV);
+       of_property_read_u32(twl6040_core_node, "ti,vddvibr-uV", &vddvibr_uV);
 
        if ((!info->vibldrv_res && !info->viblmotor_res) ||
            (!info->vibrdrv_res && !info->vibrmotor_res)) {
@@ -334,8 +323,8 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
         * When booted with Device tree the regulators are attached to the
         * parent device (twl6040 MFD core)
         */
-       ret = regulator_bulk_get(pdata ? info->dev : twl6040_core_dev,
-                                ARRAY_SIZE(info->supplies), info->supplies);
+       ret = regulator_bulk_get(twl6040_core_dev, ARRAY_SIZE(info->supplies),
+                                info->supplies);
        if (ret) {
                dev_err(info->dev, "couldn't get regulators %d\n", ret);
                return ret;
index 56536f4b9572c07757232f63430768cc8df9d6fd..b6505454bcc4575f810b468d81c419a6f8ff611c 100644 (file)
@@ -46,7 +46,6 @@
 MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>");
 MODULE_DESCRIPTION("Wistron laptop button driver");
 MODULE_LICENSE("GPL v2");
-MODULE_VERSION("0.3");
 
 static bool force; /* = 0; */
 module_param(force, bool, 0);
@@ -563,7 +562,7 @@ static struct key_entry keymap_wistron_md96500[] __initdata = {
        { KE_KEY, 0x36, {KEY_WWW} },
        { KE_WIFI, 0x30 },
        { KE_BLUETOOTH, 0x44 },
-       { KE_END, FE_UNTESTED }
+       { KE_END, 0 }
 };
 
 static struct key_entry keymap_wistron_generic[] __initdata = {
@@ -635,7 +634,7 @@ static struct key_entry keymap_prestigio[] __initdata = {
  * a list of buttons and their key codes (reported when loading this module
  * with force=1) and the output of dmidecode to $MODULE_AUTHOR.
  */
-static const struct dmi_system_id __initconst dmi_ids[] = {
+static const struct dmi_system_id dmi_ids[] __initconst = {
        {
                /* Fujitsu-Siemens Amilo Pro V2000 */
                .callback = dmi_matched,
@@ -972,6 +971,7 @@ static const struct dmi_system_id __initconst dmi_ids[] = {
        },
        { NULL, }
 };
+MODULE_DEVICE_TABLE(dmi, dmi_ids);
 
 /* Copy the good keymap, as the original ones are free'd */
 static int __init copy_keymap(void)
index 2c4db636de6cab98aeffefbe38cc34e3607d8233..23222dd5a66fb146d7b53774818c750050fb6511 100644 (file)
@@ -44,7 +44,7 @@ static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
        return 1;
 }
 
-static const struct dmi_system_id __initconst lifebook_dmi_table[] = {
+static const struct dmi_system_id lifebook_dmi_table[] __initconst = {
        {
                /* FLORA-ie 55mi */
                .matches = {
index b2420ae19e148039147a33081a651d718e8d2e4d..26386f9d25696841584f4b7f698a3cc8727fdc54 100644 (file)
@@ -1433,7 +1433,7 @@ static int synaptics_reconnect(struct psmouse *psmouse)
 
 static bool impaired_toshiba_kbc;
 
-static const struct dmi_system_id __initconst toshiba_dmi_table[] = {
+static const struct dmi_system_id toshiba_dmi_table[] __initconst = {
 #if defined(CONFIG_DMI) && defined(CONFIG_X86)
        {
                /* Toshiba Satellite */
@@ -1472,7 +1472,7 @@ static const struct dmi_system_id __initconst toshiba_dmi_table[] = {
 
 static bool broken_olpc_ec;
 
-static const struct dmi_system_id __initconst olpc_dmi_table[] = {
+static const struct dmi_system_id olpc_dmi_table[] __initconst = {
 #if defined(CONFIG_DMI) && defined(CONFIG_OLPC)
        {
                /* OLPC XO-1 or XO-1.5 */
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 3fb7727c8ea5679b9a443dc729d568d02c0788c6..8024a6d7fccbc8034b07b9b0bc9e0087275e1d94 100644 (file)
@@ -189,12 +189,6 @@ static int arc_ps2_probe(struct platform_device *pdev)
        int irq;
        int error, id, i;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "no IO memory defined\n");
-               return -EINVAL;
-       }
-
        irq = platform_get_irq_byname(pdev, "arc_ps2_irq");
        if (irq < 0) {
                dev_err(&pdev->dev, "no IRQ defined\n");
@@ -208,6 +202,7 @@ static int arc_ps2_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        arc_ps2->addr = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(arc_ps2->addr))
                return PTR_ERR(arc_ps2->addr);
index 3452708fbe3b809e5dafbd0291d69ed6c77c5dbf..fc080beffedc22acb926921507c2bd06936bb589 100644 (file)
 
 #define I8042_CTL_TIMEOUT      10000
 
-/*
- * Status register bits.
- */
-
-#define I8042_STR_PARITY       0x80
-#define I8042_STR_TIMEOUT      0x40
-#define I8042_STR_AUXDATA      0x20
-#define I8042_STR_KEYLOCK      0x10
-#define I8042_STR_CMDDAT       0x08
-#define I8042_STR_MUXERR       0x04
-#define I8042_STR_IBF          0x02
-#define        I8042_STR_OBF           0x01
-
-/*
- * Control register bits.
- */
-
-#define I8042_CTR_KBDINT       0x01
-#define I8042_CTR_AUXINT       0x02
-#define I8042_CTR_IGNKEYLOCK   0x08
-#define I8042_CTR_KBDDIS       0x10
-#define I8042_CTR_AUXDIS       0x20
-#define I8042_CTR_XLATE                0x40
-
 /*
  * Return codes.
  */
index 818aa466b5d2fb2378836b188d7d310dda6823f5..51b1d40cc286aaf224ac3e67cd500ae335bc129d 100644 (file)
@@ -183,9 +183,6 @@ static int olpc_apsp_probe(struct platform_device *pdev)
 
        np = pdev->dev.of_node;
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENOENT;
-
        priv->base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(priv->base)) {
                dev_err(&pdev->dev, "Failed to map WTM registers\n");
index aaf23aeae2ea428b4a26ea0cd99f20eeac32c964..79b69ea47f747abd035d2eb44cad9d724699ddd7 100644 (file)
@@ -221,39 +221,6 @@ static int wacom_calc_hid_res(int logical_extents, int physical_extents,
        return logical_extents / physical_extents;
 }
 
-/*
- * The physical dimension specified by the HID descriptor is likely not in
- * the "100th of a mm" units expected by wacom_calculate_touch_res. This
- * function adjusts the value of [xy]_phy based on the unit and exponent
- * provided by the HID descriptor. If an error occurs durring conversion
- * (e.g. from the unit being left unspecified) [xy]_phy is not modified.
- */
-static void wacom_fix_phy_from_hid(struct wacom_features *features)
-{
-       int xres = wacom_calc_hid_res(features->x_max, features->x_phy,
-                                       features->unit, features->unitExpo);
-       int yres = wacom_calc_hid_res(features->y_max, features->y_phy,
-                                       features->unit, features->unitExpo);
-
-       if (xres > 0 && yres > 0) {
-               features->x_phy = (100 * features->x_max) / xres;
-               features->y_phy = (100 * features->y_max) / yres;
-       }
-}
-
-/*
- * Static values for max X/Y and resolution of Pen interface is stored in
- * features. This mean physical size of active area can be computed.
- * This is useful to do when Pen and Touch have same active area of tablet.
- * This means for Touch device, we only need to find max X/Y value and we
- * have enough information to compute resolution of touch.
- */
-static void wacom_set_phy_from_res(struct wacom_features *features)
-{
-       features->x_phy = (features->x_max * 100) / features->x_resolution;
-       features->y_phy = (features->y_max * 100) / features->y_resolution;
-}
-
 static int wacom_parse_logical_collection(unsigned char *report,
                                          struct wacom_features *features)
 {
@@ -265,8 +232,6 @@ static int wacom_parse_logical_collection(unsigned char *report,
                features->pktlen = WACOM_PKGLEN_BBTOUCH3;
                features->device_type = BTN_TOOL_FINGER;
 
-               wacom_set_phy_from_res(features);
-
                features->x_max = features->y_max =
                        get_unaligned_le16(&report[10]);
 
@@ -640,9 +605,6 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
                }
        }
        error = wacom_parse_hid(intf, hid_desc, features);
-       if (error)
-               goto out;
-       wacom_fix_phy_from_hid(features);
 
  out:
        return error;
@@ -1228,7 +1190,6 @@ static void wacom_wireless_work(struct work_struct *work)
                        *((struct wacom_features *)id->driver_info);
                wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
                wacom_wac2->features.device_type = BTN_TOOL_FINGER;
-               wacom_set_phy_from_res(&wacom_wac2->features);
                wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
                error = wacom_register_input(wacom2);
                if (error)
@@ -1251,6 +1212,33 @@ fail1:
        return;
 }
 
+/*
+ * Not all devices report physical dimensions from HID.
+ * Compute the default from hardcoded logical dimension
+ * and resolution before driver overwrites them.
+ */
+static void wacom_set_default_phy(struct wacom_features *features)
+{
+       if (features->x_resolution) {
+               features->x_phy = (features->x_max * 100) /
+                                       features->x_resolution;
+               features->y_phy = (features->y_max * 100) /
+                                       features->y_resolution;
+       }
+}
+
+static void wacom_calculate_res(struct wacom_features *features)
+{
+       features->x_resolution = wacom_calc_hid_res(features->x_max,
+                                                   features->x_phy,
+                                                   features->unit,
+                                                   features->unitExpo);
+       features->y_resolution = wacom_calc_hid_res(features->y_max,
+                                                   features->y_phy,
+                                                   features->unit,
+                                                   features->unitExpo);
+}
+
 static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        struct usb_device *dev = interface_to_usbdev(intf);
@@ -1297,6 +1285,9 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 
        endpoint = &intf->cur_altsetting->endpoint[0].desc;
 
+       /* set the default size in case we do not get them from hid */
+       wacom_set_default_phy(features);
+
        /* Retrieve the physical and logical size for touch devices */
        error = wacom_retrieve_hid_descriptor(intf, features);
        if (error)
@@ -1312,8 +1303,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
                        features->device_type = BTN_TOOL_FINGER;
                        features->pktlen = WACOM_PKGLEN_BBTOUCH3;
 
-                       wacom_set_phy_from_res(features);
-
                        features->x_max = 4096;
                        features->y_max = 4096;
                } else {
@@ -1323,6 +1312,13 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 
        wacom_setup_device_quirks(features);
 
+       /* set unit to "100th of a mm" for devices not reported by HID */
+       if (!features->unit) {
+               features->unit = 0x11;
+               features->unitExpo = 16 - 3;
+       }
+       wacom_calculate_res(features);
+
        strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
 
        if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
@@ -1334,7 +1330,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
                                " Pen" : " Finger",
                        sizeof(wacom_wac->name));
 
-
                other_dev = wacom_get_sibling(dev, features->oVid, features->oPid);
                if (other_dev == NULL || wacom_get_usbdev_data(other_dev) == NULL)
                        other_dev = dev;
@@ -1366,8 +1361,10 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        usb_set_intfdata(intf, wacom);
 
        if (features->quirks & WACOM_QUIRK_MONITOR) {
-               if (usb_submit_urb(wacom->irq, GFP_KERNEL))
+               if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
+                       error = -EIO;
                        goto fail5;
+               }
        }
 
        return 0;
@@ -1422,8 +1419,8 @@ static int wacom_resume(struct usb_interface *intf)
        wacom_query_tablet_data(intf, features);
        wacom_led_control(wacom);
 
-       if ((wacom->open || features->quirks & WACOM_QUIRK_MONITOR)
-            && usb_submit_urb(wacom->irq, GFP_NOIO) < 0)
+       if ((wacom->open || (features->quirks & WACOM_QUIRK_MONITOR)) &&
+           usb_submit_urb(wacom->irq, GFP_NOIO) < 0)
                rv = -EIO;
 
        mutex_unlock(&wacom->lock);
index f3e91f0b57ae045323da8048ed6a9b5a85f8d4a1..b2aa503c16b1fb08c7d94817c533794d6d9375bd 100644 (file)
@@ -1445,13 +1445,6 @@ void wacom_setup_device_quirks(struct wacom_features *features)
        }
 }
 
-static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
-                                             unsigned int physical_max)
-{
-       /* Touch physical dimensions are in 100th of mm */
-       return (logical_max * 100) / physical_max;
-}
-
 static void wacom_abs_set_axis(struct input_dev *input_dev,
                               struct wacom_wac *wacom_wac)
 {
@@ -1475,11 +1468,9 @@ static void wacom_abs_set_axis(struct input_dev *input_dev,
                        input_set_abs_params(input_dev, ABS_Y, 0,
                                features->y_max, features->y_fuzz, 0);
                        input_abs_set_res(input_dev, ABS_X,
-                               wacom_calculate_touch_res(features->x_max,
-                                                       features->x_phy));
+                                         features->x_resolution);
                        input_abs_set_res(input_dev, ABS_Y,
-                               wacom_calculate_touch_res(features->y_max,
-                                                       features->y_phy));
+                                         features->y_resolution);
                }
 
                if (features->touch_max > 1) {
@@ -1488,11 +1479,9 @@ static void wacom_abs_set_axis(struct input_dev *input_dev,
                        input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
                                features->y_max, features->y_fuzz, 0);
                        input_abs_set_res(input_dev, ABS_MT_POSITION_X,
-                               wacom_calculate_touch_res(features->x_max,
-                                                       features->x_phy));
+                                         features->x_resolution);
                        input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
-                               wacom_calculate_touch_res(features->y_max,
-                                                       features->y_phy));
+                                         features->y_resolution);
                }
        }
 }
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 96e0eedcc7e5876a871c72f909653359a154260e..8c651985a5c44929f083c99e881be5431bca9cad 100644 (file)
@@ -291,7 +291,7 @@ err_free_mem:
        return err;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int cy8ctmg110_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -319,9 +319,9 @@ static int cy8ctmg110_resume(struct device *dev)
        }
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
-#endif
 
 static int cy8ctmg110_remove(struct i2c_client *client)
 {
@@ -351,9 +351,7 @@ static struct i2c_driver cy8ctmg110_driver = {
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = CY8CTMG110_DRIVER_NAME,
-#ifdef CONFIG_PM
                .pm     = &cy8ctmg110_pm,
-#endif
        },
        .id_table       = cy8ctmg110_idtable,
        .probe          = cy8ctmg110_probe,
index edcf7993034bc390ffe6d34c6b129ae4afd79292..d038575f49db3a6d70e16ee640fb67cfbcab24be 100644 (file)
@@ -1246,9 +1246,6 @@ static void cyttsp4_watchdog_timer(unsigned long handle)
 
        dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__);
 
-       if (!cd)
-               return;
-
        if (!work_pending(&cd->watchdog_work))
                schedule_work(&cd->watchdog_work);
 
@@ -1552,106 +1549,6 @@ exit:
        return rc;
 }
 
-static int cyttsp4_core_sleep(struct cyttsp4 *cd)
-{
-       int rc;
-
-       rc = cyttsp4_request_exclusive(cd, cd->dev,
-                       CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT);
-       if (rc < 0) {
-               dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
-                               __func__, cd->exclusive_dev, cd->dev);
-               return 0;
-       }
-
-       rc = cyttsp4_core_sleep_(cd);
-
-       if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
-               dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
-       else
-               dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
-
-       return rc;
-}
-
-static int cyttsp4_core_wake_(struct cyttsp4 *cd)
-{
-       struct device *dev = cd->dev;
-       int rc;
-       u8 mode;
-       int t;
-
-       /* Already woken? */
-       mutex_lock(&cd->system_lock);
-       if (cd->sleep_state == SS_SLEEP_OFF) {
-               mutex_unlock(&cd->system_lock);
-               return 0;
-       }
-       cd->int_status &= ~CY_INT_IGNORE;
-       cd->int_status |= CY_INT_AWAKE;
-       cd->sleep_state = SS_WAKING;
-
-       if (cd->cpdata->power) {
-               dev_dbg(dev, "%s: Power up HW\n", __func__);
-               rc = cd->cpdata->power(cd->cpdata, 1, dev, &cd->ignore_irq);
-       } else {
-               dev_dbg(dev, "%s: No power function\n", __func__);
-               rc = -ENOSYS;
-       }
-       if (rc < 0) {
-               dev_err(dev, "%s: HW Power up fails r=%d\n",
-                               __func__, rc);
-
-               /* Initiate a read transaction to wake up */
-               cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
-       } else
-               dev_vdbg(cd->dev, "%s: HW power up succeeds\n",
-                       __func__);
-       mutex_unlock(&cd->system_lock);
-
-       t = wait_event_timeout(cd->wait_q,
-                       (cd->int_status & CY_INT_AWAKE) == 0,
-                       msecs_to_jiffies(CY_CORE_WAKEUP_TIMEOUT));
-       if (IS_TMO(t)) {
-               dev_err(dev, "%s: TMO waiting for wakeup\n", __func__);
-               mutex_lock(&cd->system_lock);
-               cd->int_status &= ~CY_INT_AWAKE;
-               /* Try starting up */
-               cyttsp4_queue_startup_(cd);
-               mutex_unlock(&cd->system_lock);
-       }
-
-       mutex_lock(&cd->system_lock);
-       cd->sleep_state = SS_SLEEP_OFF;
-       mutex_unlock(&cd->system_lock);
-
-       cyttsp4_start_wd_timer(cd);
-
-       return 0;
-}
-
-static int cyttsp4_core_wake(struct cyttsp4 *cd)
-{
-       int rc;
-
-       rc = cyttsp4_request_exclusive(cd, cd->dev,
-                       CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT);
-       if (rc < 0) {
-               dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
-                               __func__, cd->exclusive_dev, cd->dev);
-               return 0;
-       }
-
-       rc = cyttsp4_core_wake_(cd);
-
-       if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
-               dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
-       else
-               dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
-
-       return rc;
-}
-
 static int cyttsp4_startup_(struct cyttsp4 *cd)
 {
        int retry = CY_CORE_STARTUP_RETRY_COUNT;
@@ -1821,6 +1718,106 @@ static void cyttsp4_free_si_ptrs(struct cyttsp4 *cd)
 }
 
 #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
+static int cyttsp4_core_sleep(struct cyttsp4 *cd)
+{
+       int rc;
+
+       rc = cyttsp4_request_exclusive(cd, cd->dev,
+                       CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT);
+       if (rc < 0) {
+               dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+                               __func__, cd->exclusive_dev, cd->dev);
+               return 0;
+       }
+
+       rc = cyttsp4_core_sleep_(cd);
+
+       if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
+               dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+       else
+               dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
+
+       return rc;
+}
+
+static int cyttsp4_core_wake_(struct cyttsp4 *cd)
+{
+       struct device *dev = cd->dev;
+       int rc;
+       u8 mode;
+       int t;
+
+       /* Already woken? */
+       mutex_lock(&cd->system_lock);
+       if (cd->sleep_state == SS_SLEEP_OFF) {
+               mutex_unlock(&cd->system_lock);
+               return 0;
+       }
+       cd->int_status &= ~CY_INT_IGNORE;
+       cd->int_status |= CY_INT_AWAKE;
+       cd->sleep_state = SS_WAKING;
+
+       if (cd->cpdata->power) {
+               dev_dbg(dev, "%s: Power up HW\n", __func__);
+               rc = cd->cpdata->power(cd->cpdata, 1, dev, &cd->ignore_irq);
+       } else {
+               dev_dbg(dev, "%s: No power function\n", __func__);
+               rc = -ENOSYS;
+       }
+       if (rc < 0) {
+               dev_err(dev, "%s: HW Power up fails r=%d\n",
+                               __func__, rc);
+
+               /* Initiate a read transaction to wake up */
+               cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
+       } else
+               dev_vdbg(cd->dev, "%s: HW power up succeeds\n",
+                       __func__);
+       mutex_unlock(&cd->system_lock);
+
+       t = wait_event_timeout(cd->wait_q,
+                       (cd->int_status & CY_INT_AWAKE) == 0,
+                       msecs_to_jiffies(CY_CORE_WAKEUP_TIMEOUT));
+       if (IS_TMO(t)) {
+               dev_err(dev, "%s: TMO waiting for wakeup\n", __func__);
+               mutex_lock(&cd->system_lock);
+               cd->int_status &= ~CY_INT_AWAKE;
+               /* Try starting up */
+               cyttsp4_queue_startup_(cd);
+               mutex_unlock(&cd->system_lock);
+       }
+
+       mutex_lock(&cd->system_lock);
+       cd->sleep_state = SS_SLEEP_OFF;
+       mutex_unlock(&cd->system_lock);
+
+       cyttsp4_start_wd_timer(cd);
+
+       return 0;
+}
+
+static int cyttsp4_core_wake(struct cyttsp4 *cd)
+{
+       int rc;
+
+       rc = cyttsp4_request_exclusive(cd, cd->dev,
+                       CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT);
+       if (rc < 0) {
+               dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+                               __func__, cd->exclusive_dev, cd->dev);
+               return 0;
+       }
+
+       rc = cyttsp4_core_wake_(cd);
+
+       if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
+               dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+       else
+               dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
+
+       return rc;
+}
+
 static int cyttsp4_core_suspend(struct device *dev)
 {
        struct cyttsp4 *cd = dev_get_drvdata(dev);
index 8fe5086c8d2e0b0d54f291a7b1f1a3f90293cad9..1ce3d29ffca5a11e2411936cce7999c089d68764 100644 (file)
@@ -264,7 +264,7 @@ static int eeti_ts_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int eeti_ts_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -302,9 +302,9 @@ static int eeti_ts_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
-#endif
 
 static const struct i2c_device_id eeti_ts_id[] = {
        { "eeti_ts", 0 },
@@ -315,9 +315,7 @@ MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
 static struct i2c_driver eeti_ts_driver = {
        .driver = {
                .name = "eeti_ts",
-#ifdef CONFIG_PM
                .pm = &eeti_ts_pm,
-#endif
        },
        .probe = eeti_ts_probe,
        .remove = eeti_ts_remove,
index 6c4fb84369575df40bbfe8bc6a7addcd7a913e15..66500852341b66319b634133b3f0930f3dc3f2ec 100644 (file)
@@ -221,7 +221,7 @@ static struct isa_driver htcpen_isa_driver = {
        }
 };
 
-static struct dmi_system_id __initdata htcshift_dmi_table[] = {
+static struct dmi_system_id htcshift_dmi_table[] __initdata = {
        {
                .ident = "Shift",
                .matches = {
index 00bc6caa27f5c296c073d46802197ded10e1e1a5..9f84fcd08732f84726af16060107070cb2108b54 100644 (file)
@@ -181,12 +181,11 @@ static int max11801_ts_probe(struct i2c_client *client,
        struct input_dev *input_dev;
        int error;
 
-       data = kzalloc(sizeof(struct max11801_data), GFP_KERNEL);
-       input_dev = input_allocate_device();
+       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+       input_dev = devm_input_allocate_device(&client->dev);
        if (!data || !input_dev) {
                dev_err(&client->dev, "Failed to allocate memory\n");
-               error = -ENOMEM;
-               goto err_free_mem;
+               return -ENOMEM;
        }
 
        data->client = client;
@@ -205,38 +204,21 @@ static int max11801_ts_probe(struct i2c_client *client,
 
        max11801_ts_phy_init(data);
 
-       error = request_threaded_irq(client->irq, NULL, max11801_ts_interrupt,
-                                    IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-                                    "max11801_ts", data);
+       error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+                                         max11801_ts_interrupt,
+                                         IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                         "max11801_ts", data);
        if (error) {
                dev_err(&client->dev, "Failed to register interrupt\n");
-               goto err_free_mem;
+               return error;
        }
 
        error = input_register_device(data->input_dev);
        if (error)
-               goto err_free_irq;
+               return error;
 
        i2c_set_clientdata(client, data);
        return 0;
-
-err_free_irq:
-       free_irq(client->irq, data);
-err_free_mem:
-       input_free_device(input_dev);
-       kfree(data);
-       return error;
-}
-
-static int max11801_ts_remove(struct i2c_client *client)
-{
-       struct max11801_data *data = i2c_get_clientdata(client);
-
-       free_irq(client->irq, data);
-       input_unregister_device(data->input_dev);
-       kfree(data);
-
-       return 0;
 }
 
 static const struct i2c_device_id max11801_ts_id[] = {
@@ -252,7 +234,6 @@ static struct i2c_driver max11801_ts_driver = {
        },
        .id_table       = max11801_ts_id,
        .probe          = max11801_ts_probe,
-       .remove         = max11801_ts_remove,
 };
 
 module_i2c_driver(max11801_ts_driver);
index 820d85c4a4a0f8c2b8fc813adfa30a07c529a953..c880ebaf155372eaa7460491258502c9c2d35dcd 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"
@@ -42,7 +52,7 @@ config AMD_IOMMU
        select PCI_PRI
        select PCI_PASID
        select IOMMU_API
-       depends on X86_64 && PCI && ACPI && X86_IO_APIC
+       depends on X86_64 && PCI && ACPI
        ---help---
          With this option you can enable support for AMD IOMMU hardware in
          your system. An IOMMU is a hardware component which provides
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..181c9ba929cdfa131123639862cdefb2587c8cf6 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,20 +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 INVALID_IRPTNDX                        0xff
+
+#define ARM_SMMU_CB_ASID(cfg)          ((cfg)->cbndx)
+#define ARM_SMMU_CB_VMID(cfg)          ((cfg)->cbndx + 1)
 
 struct arm_smmu_domain {
        /*
@@ -533,6 +535,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 +611,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 +625,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 +642,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 +712,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 +771,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 +807,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 +825,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;
@@ -830,7 +841,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
        if (IS_ERR_VALUE(ret)) {
                dev_err(smmu->dev, "failed to request context IRQ %d (%u)\n",
                        root_cfg->irptndx, irq);
-               root_cfg->irptndx = -1;
+               root_cfg->irptndx = INVALID_IRPTNDX;
                goto out_free_context;
        }
 
@@ -840,8 +851,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 +859,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;
 
-       if (root_cfg->irptndx != -1) {
+       /* 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 != INVALID_IRPTNDX) {
                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 +973,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 +1218,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 +1434,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 +1559,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 +1569,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);
@@ -1838,8 +1858,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
                goto out_put_parent;
        }
 
-       arm_smmu_device_reset(smmu);
-
        for (i = 0; i < smmu->num_global_irqs; ++i) {
                err = request_irq(smmu->irqs[i],
                                  arm_smmu_global_fault,
@@ -1857,6 +1875,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
        spin_lock(&arm_smmu_devices_lock);
        list_add(&smmu->list, &arm_smmu_devices);
        spin_unlock(&arm_smmu_devices_lock);
+
+       arm_smmu_device_reset(smmu);
        return 0;
 
 out_free_irqs:
@@ -1906,7 +1926,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)
@@ -1947,10 +1967,10 @@ static int __init arm_smmu_init(void)
                return ret;
 
        /* Oh, for a proper bus abstraction */
-       if (!iommu_present(&platform_bus_type));
+       if (!iommu_present(&platform_bus_type))
                bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
 
-       if (!iommu_present(&amba_bustype));
+       if (!iommu_present(&amba_bustype))
                bus_set_iommu(&amba_bustype, &arm_smmu_ops);
 
        return 0;
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);
similarity index 63%
rename from arch/arm/mach-mmp/irq.c
rename to drivers/irqchip/irq-mmp.c
index 3c71246cd99459993a9b61c638cfb17f432f1159..2cb7cd0bc2f527136d8e430137436480332d2512 100644 (file)
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 
-#include <mach/irqs.h>
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
 
-#ifdef CONFIG_CPU_MMP2
-#include <mach/pm-mmp2.h>
-#endif
-#ifdef CONFIG_CPU_PXA910
-#include <mach/pm-pxa910.h>
-#endif
-
-#include "common.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;
@@ -54,7 +55,7 @@ struct mmp_intc_conf {
        unsigned int    conf_mask;
 };
 
-void __iomem *mmp_icu_base;
+static void __iomem *mmp_icu_base;
 static struct icu_chip_data icu_data[MAX_ICU_NR];
 static int max_icu_nr;
 
@@ -122,7 +123,7 @@ static void icu_unmask_irq(struct irq_data *d)
        }
 }
 
-static struct irq_chip icu_irq_chip = {
+struct irq_chip icu_irq_chip = {
        .name           = "icu_irq",
        .irq_mask       = icu_mask_irq,
        .irq_mask_ack   = icu_mask_ack_irq,
@@ -193,6 +194,32 @@ static struct mmp_intc_conf mmp2_conf = {
        .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)
 {
@@ -214,15 +241,13 @@ void __init icu_init_irq(void)
                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
+       set_handle_irq(mmp_handle_irq);
 }
 
 /* MMP2 (ARMv7) */
 void __init mmp2_init_icu(void)
 {
-       int irq;
+       int irq, end;
 
        max_icu_nr = 8;
        mmp_icu_base = ioremap(0xd4282000, 0x1000);
@@ -236,11 +261,12 @@ void __init mmp2_init_icu(void)
                                                   &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].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 = IRQ_MMP2_PMIC_BASE;
+       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,
@@ -249,7 +275,7 @@ void __init mmp2_init_icu(void)
        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].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,
@@ -258,7 +284,7 @@ void __init mmp2_init_icu(void)
        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].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,
@@ -267,7 +293,7 @@ void __init mmp2_init_icu(void)
        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].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,
@@ -276,7 +302,7 @@ void __init mmp2_init_icu(void)
        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].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,
@@ -285,7 +311,7 @@ void __init mmp2_init_icu(void)
        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].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,
@@ -294,170 +320,176 @@ void __init mmp2_init_icu(void)
        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].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]);
-       for (irq = 0; irq < IRQ_MMP2_MUX_END; irq++) {
+       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));
-               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:
+               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);
-                       break;
-               default:
+               } else {
                        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
+       set_handle_irq(mmp2_handle_irq);
 }
 
 #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)
+static int __init mmp_init_bases(struct device_node *node)
 {
-       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;
+       int ret, nr_irqs, irq, i = 0;
 
-       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;
-               }
+       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;
+       }
 
-               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;
+       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 (!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));
+               if (!irq)
+                       icu_data[0].virq_base = ret;
        }
-       max_icu_nr = i;
+       icu_data[0].nr_irqs = nr_irqs;
        return 0;
 err:
-       of_node_put(node);
-       max_icu_nr = i;
-       return ret;
+       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;
 }
 
-void __init mmp_dt_irq_init(void)
+static int __init mmp_of_init(struct device_node *node,
+                             struct device_node *parent)
 {
-       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;
+       int ret;
 
-       ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs);
+       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;
+               return -EINVAL;
        }
-
-       mmp_icu_base = of_iomap(node, 0);
-       if (!mmp_icu_base) {
-               pr_err("Failed to get interrupt controller register\n");
-               return;
+       ret = of_address_to_resource(node, 0, &res);
+       if (ret < 0) {
+               pr_err("Not found reg property\n");
+               return -EINVAL;
        }
-
-       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[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[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,
+       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[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;
+                                                  &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:
-       iounmap(mmp_icu_base);
+       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 eba380d7b17f18653818bdeedaa9f56386460af1..42d2b893ea67fff1096ce4b7567a247ed194c9c0 100644 (file)
@@ -325,7 +325,6 @@ static int omap2_mbox_remove(struct platform_device *pdev)
        kfree(privblk);
        kfree(mboxblk);
        kfree(list);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
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 b39f6f0b45f27b89f29e580844e41d8d315d9c18..0f12382aa35d6c939b53967b205639134e181eae 100644 (file)
@@ -498,7 +498,7 @@ struct cached_dev {
         */
        atomic_t                has_dirty;
 
-       struct ratelimit        writeback_rate;
+       struct bch_ratelimit    writeback_rate;
        struct delayed_work     writeback_rate_update;
 
        /*
@@ -507,10 +507,9 @@ struct cached_dev {
         */
        sector_t                last_read;
 
-       /* Number of writeback bios in flight */
-       atomic_t                in_flight;
+       /* Limit number of writeback bios in flight */
+       struct semaphore        in_flight;
        struct closure_with_timer writeback;
-       struct closure_waitlist writeback_wait;
 
        struct keybuf           writeback_keys;
 
index 8010eed06a51c8320786a1c49463c98c8aa70555..22d1ae72c2826a53b67656a59ea717a62a3b95a4 100644 (file)
@@ -926,28 +926,45 @@ struct bkey *bch_next_recurse_key(struct btree *b, struct bkey *search)
 
 /* Mergesort */
 
+static void sort_key_next(struct btree_iter *iter,
+                         struct btree_iter_set *i)
+{
+       i->k = bkey_next(i->k);
+
+       if (i->k == i->end)
+               *i = iter->data[--iter->used];
+}
+
 static void btree_sort_fixup(struct btree_iter *iter)
 {
        while (iter->used > 1) {
                struct btree_iter_set *top = iter->data, *i = top + 1;
-               struct bkey *k;
 
                if (iter->used > 2 &&
                    btree_iter_cmp(i[0], i[1]))
                        i++;
 
-               for (k = i->k;
-                    k != i->end && bkey_cmp(top->k, &START_KEY(k)) > 0;
-                    k = bkey_next(k))
-                       if (top->k > i->k)
-                               __bch_cut_front(top->k, k);
-                       else if (KEY_SIZE(k))
-                               bch_cut_back(&START_KEY(k), top->k);
-
-               if (top->k < i->k || k == i->k)
+               if (bkey_cmp(top->k, &START_KEY(i->k)) <= 0)
                        break;
 
-               heap_sift(iter, i - top, btree_iter_cmp);
+               if (!KEY_SIZE(i->k)) {
+                       sort_key_next(iter, i);
+                       heap_sift(iter, i - top, btree_iter_cmp);
+                       continue;
+               }
+
+               if (top->k > i->k) {
+                       if (bkey_cmp(top->k, i->k) >= 0)
+                               sort_key_next(iter, i);
+                       else
+                               bch_cut_front(top->k, i->k);
+
+                       heap_sift(iter, i - top, btree_iter_cmp);
+               } else {
+                       /* can't happen because of comparison func */
+                       BUG_ON(!bkey_cmp(&START_KEY(top->k), &START_KEY(i->k)));
+                       bch_cut_back(&START_KEY(i->k), top->k);
+               }
        }
 }
 
index ee372884c405444886671901e45c3834626f383a..f42fc7ed9cd63b14fd4cf54a879dfd9d046584d1 100644 (file)
@@ -255,7 +255,7 @@ void bch_btree_node_read(struct btree *b)
 
        return;
 err:
-       bch_cache_set_error(b->c, "io error reading bucket %lu",
+       bch_cache_set_error(b->c, "io error reading bucket %zu",
                            PTR_BUCKET_NR(b->c, &b->key, 0));
 }
 
@@ -597,27 +597,22 @@ 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)
+       if (sc->gfp_mask & __GFP_IO)
                mutex_lock(&c->bucket_lock);
        else if (!mutex_trylock(&c->bucket_lock))
                return -1;
@@ -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 ba95ab84b2be5a5a32292625d229bb29e051a53d..8435f81e5d858012e8aca6be8204e923a34b1d01 100644 (file)
@@ -153,7 +153,8 @@ int bch_journal_read(struct cache_set *c, struct list_head *list,
                bitmap_zero(bitmap, SB_JOURNAL_BUCKETS);
                pr_debug("%u journal buckets", ca->sb.njournal_buckets);
 
-               /* Read journal buckets ordered by golden ratio hash to quickly
+               /*
+                * Read journal buckets ordered by golden ratio hash to quickly
                 * find a sequence of buckets with valid journal entries
                 */
                for (i = 0; i < ca->sb.njournal_buckets; i++) {
@@ -166,18 +167,20 @@ int bch_journal_read(struct cache_set *c, struct list_head *list,
                                goto bsearch;
                }
 
-               /* If that fails, check all the buckets we haven't checked
+               /*
+                * If that fails, check all the buckets we haven't checked
                 * already
                 */
                pr_debug("falling back to linear search");
 
-               for (l = 0; l < ca->sb.njournal_buckets; l++) {
-                       if (test_bit(l, bitmap))
-                               continue;
-
+               for (l = find_first_zero_bit(bitmap, ca->sb.njournal_buckets);
+                    l < ca->sb.njournal_buckets;
+                    l = find_next_zero_bit(bitmap, ca->sb.njournal_buckets, l + 1))
                        if (read_bucket(l))
                                goto bsearch;
-               }
+
+               if (list_empty(list))
+                       continue;
 bsearch:
                /* Binary search */
                m = r = find_next_bit(bitmap, ca->sb.njournal_buckets, l + 1);
@@ -197,10 +200,12 @@ bsearch:
                                r = m;
                }
 
-               /* Read buckets in reverse order until we stop finding more
+               /*
+                * Read buckets in reverse order until we stop finding more
                 * journal entries
                 */
-               pr_debug("finishing up");
+               pr_debug("finishing up: m %u njournal_buckets %u",
+                        m, ca->sb.njournal_buckets);
                l = m;
 
                while (1) {
@@ -228,9 +233,10 @@ bsearch:
                        }
        }
 
-       c->journal.seq = list_entry(list->prev,
-                                   struct journal_replay,
-                                   list)->j.seq;
+       if (!list_empty(list))
+               c->journal.seq = list_entry(list->prev,
+                                           struct journal_replay,
+                                           list)->j.seq;
 
        return 0;
 #undef read_bucket
@@ -428,7 +434,7 @@ static void do_journal_discard(struct cache *ca)
                return;
        }
 
-       switch (atomic_read(&ja->discard_in_flight) == DISCARD_IN_FLIGHT) {
+       switch (atomic_read(&ja->discard_in_flight)) {
        case DISCARD_IN_FLIGHT:
                return;
 
@@ -689,6 +695,7 @@ void bch_journal_meta(struct cache_set *c, struct closure *cl)
                if (cl)
                        BUG_ON(!closure_wait(&w->wait, cl));
 
+               closure_flush(&c->journal.io);
                __journal_try_write(c, true);
        }
 }
index 786a1a4f74d853fafe3ab2ae263d2ecf780134aa..b6a74bcbb08f8800bae2aa57888498a46eb85f69 100644 (file)
@@ -996,17 +996,19 @@ static void request_write(struct cached_dev *dc, struct search *s)
                closure_bio_submit(bio, cl, s->d);
        } else {
                bch_writeback_add(dc);
+               s->op.cache_bio = bio;
 
-               if (s->op.flush_journal) {
+               if (bio->bi_rw & REQ_FLUSH) {
                        /* Also need to send a flush to the backing device */
-                       s->op.cache_bio = bio_clone_bioset(bio, GFP_NOIO,
-                                                          dc->disk.bio_split);
-
-                       bio->bi_size = 0;
-                       bio->bi_vcnt = 0;
-                       closure_bio_submit(bio, cl, s->d);
-               } else {
-                       s->op.cache_bio = bio;
+                       struct bio *flush = bio_alloc_bioset(0, GFP_NOIO,
+                                                            dc->disk.bio_split);
+
+                       flush->bi_rw    = WRITE_FLUSH;
+                       flush->bi_bdev  = bio->bi_bdev;
+                       flush->bi_end_io = request_endio;
+                       flush->bi_private = cl;
+
+                       closure_bio_submit(flush, cl, s->d);
                }
        }
 out:
index 12a2c2846f994a1e2d51bf79374426df96893418..924dcfdae11102256e1ce193eefc01d82cc173cc 100644 (file)
@@ -223,8 +223,13 @@ STORE(__cached_dev)
        }
 
        if (attr == &sysfs_label) {
-               /* note: endlines are preserved */
-               memcpy(dc->sb.label, buf, SB_LABEL_SIZE);
+               if (size > SB_LABEL_SIZE)
+                       return -EINVAL;
+               memcpy(dc->sb.label, buf, size);
+               if (size < SB_LABEL_SIZE)
+                       dc->sb.label[size] = '\0';
+               if (size && dc->sb.label[size - 1] == '\n')
+                       dc->sb.label[size - 1] = '\0';
                bch_write_bdev_super(dc, NULL);
                if (dc->disk.c) {
                        memcpy(dc->disk.c->uuids[dc->disk.id].label,
@@ -556,7 +561,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 98eb81159a22ba9f9e88fec53127e2e338ae3d4d..420dad545c7d8a01e8b5c18d26db4b25677fd334 100644 (file)
@@ -190,7 +190,16 @@ void bch_time_stats_update(struct time_stats *stats, uint64_t start_time)
        stats->last = now ?: 1;
 }
 
-unsigned bch_next_delay(struct ratelimit *d, uint64_t done)
+/**
+ * bch_next_delay() - increment @d by the amount of work done, and return how
+ * long to delay until the next time to do some work.
+ *
+ * @d - the struct bch_ratelimit to update
+ * @done - the amount of work done, in arbitrary units
+ *
+ * Returns the amount of time to delay by, in jiffies
+ */
+uint64_t bch_next_delay(struct bch_ratelimit *d, uint64_t done)
 {
        uint64_t now = local_clock();
 
index 1ae2a73ad85f5628b5292b769d79b0f28252f4ca..ea345c6896f47777942b64f88810c99d4cbc278e 100644 (file)
@@ -450,17 +450,23 @@ read_attribute(name ## _last_ ## frequency_units)
        (ewma) >> factor;                                               \
 })
 
-struct ratelimit {
+struct bch_ratelimit {
+       /* Next time we want to do some work, in nanoseconds */
        uint64_t                next;
+
+       /*
+        * Rate at which we want to do work, in units per nanosecond
+        * The units here correspond to the units passed to bch_next_delay()
+        */
        unsigned                rate;
 };
 
-static inline void ratelimit_reset(struct ratelimit *d)
+static inline void bch_ratelimit_reset(struct bch_ratelimit *d)
 {
        d->next = local_clock();
 }
 
-unsigned bch_next_delay(struct ratelimit *d, uint64_t done);
+uint64_t bch_next_delay(struct bch_ratelimit *d, uint64_t done);
 
 #define __DIV_SAFE(n, d, zero)                                         \
 ({                                                                     \
index 22cbff551628f3c9cff87ccc35563c09974f03b3..ba3ee48320f2a38509adb2603f766c55e67f1da1 100644 (file)
@@ -94,11 +94,15 @@ static void update_writeback_rate(struct work_struct *work)
 
 static unsigned writeback_delay(struct cached_dev *dc, unsigned sectors)
 {
+       uint64_t ret;
+
        if (atomic_read(&dc->disk.detaching) ||
            !dc->writeback_percent)
                return 0;
 
-       return bch_next_delay(&dc->writeback_rate, sectors * 10000000ULL);
+       ret = bch_next_delay(&dc->writeback_rate, sectors * 10000000ULL);
+
+       return min_t(uint64_t, ret, HZ);
 }
 
 /* Background writeback */
@@ -208,7 +212,7 @@ normal_refill:
 
        up_write(&dc->writeback_lock);
 
-       ratelimit_reset(&dc->writeback_rate);
+       bch_ratelimit_reset(&dc->writeback_rate);
 
        /* Punt to workqueue only so we don't recurse and blow the stack */
        continue_at(cl, read_dirty, dirty_wq);
@@ -318,9 +322,7 @@ static void write_dirty_finish(struct closure *cl)
        }
 
        bch_keybuf_del(&dc->writeback_keys, w);
-       atomic_dec_bug(&dc->in_flight);
-
-       closure_wake_up(&dc->writeback_wait);
+       up(&dc->in_flight);
 
        closure_return_with_destructor(cl, dirty_io_destructor);
 }
@@ -349,7 +351,7 @@ static void write_dirty(struct closure *cl)
 
        closure_bio_submit(&io->bio, cl, &io->dc->disk);
 
-       continue_at(cl, write_dirty_finish, dirty_wq);
+       continue_at(cl, write_dirty_finish, system_wq);
 }
 
 static void read_dirty_endio(struct bio *bio, int error)
@@ -369,7 +371,7 @@ static void read_dirty_submit(struct closure *cl)
 
        closure_bio_submit(&io->bio, cl, &io->dc->disk);
 
-       continue_at(cl, write_dirty, dirty_wq);
+       continue_at(cl, write_dirty, system_wq);
 }
 
 static void read_dirty(struct closure *cl)
@@ -394,12 +396,8 @@ static void read_dirty(struct closure *cl)
 
                if (delay > 0 &&
                    (KEY_START(&w->key) != dc->last_read ||
-                    jiffies_to_msecs(delay) > 50)) {
-                       w->private = NULL;
-
-                       closure_delay(&dc->writeback, delay);
-                       continue_at(cl, read_dirty, dirty_wq);
-               }
+                    jiffies_to_msecs(delay) > 50))
+                       delay = schedule_timeout_uninterruptible(delay);
 
                dc->last_read   = KEY_OFFSET(&w->key);
 
@@ -424,15 +422,10 @@ static void read_dirty(struct closure *cl)
 
                trace_bcache_writeback(&w->key);
 
-               closure_call(&io->cl, read_dirty_submit, NULL, &dc->disk.cl);
+               down(&dc->in_flight);
+               closure_call(&io->cl, read_dirty_submit, NULL, cl);
 
                delay = writeback_delay(dc, KEY_SIZE(&w->key));
-
-               atomic_inc(&dc->in_flight);
-
-               if (!closure_wait_event(&dc->writeback_wait, cl,
-                                       atomic_read(&dc->in_flight) < 64))
-                       continue_at(cl, read_dirty, dirty_wq);
        }
 
        if (0) {
@@ -442,7 +435,11 @@ err:
                bch_keybuf_del(&dc->writeback_keys, w);
        }
 
-       refill_dirty(cl);
+       /*
+        * Wait for outstanding writeback IOs to finish (and keybuf slots to be
+        * freed) before refilling again
+        */
+       continue_at(cl, refill_dirty, dirty_wq);
 }
 
 /* Init */
@@ -484,6 +481,7 @@ void bch_sectors_dirty_init(struct cached_dev *dc)
 
 void bch_cached_dev_writeback_init(struct cached_dev *dc)
 {
+       sema_init(&dc->in_flight, 64);
        closure_init_unlocked(&dc->writeback);
        init_rwsem(&dc->writeback_lock);
 
@@ -513,7 +511,7 @@ void bch_writeback_exit(void)
 
 int __init bch_writeback_init(void)
 {
-       dirty_wq = create_singlethread_workqueue("bcache_writeback");
+       dirty_wq = create_workqueue("bcache_writeback");
        if (!dirty_wq)
                return -ENOMEM;
 
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 ea49834377c8e17b6e8b221e4bd58389a8d7c32e..2a20986a2fec9701cd25e443c990f2b7a8479f9f 100644 (file)
@@ -19,8 +19,6 @@
 #define DM_MSG_PREFIX "io"
 
 #define DM_IO_MAX_REGIONS      BITS_PER_LONG
-#define MIN_IOS                16
-#define MIN_BIOS       16
 
 struct dm_io_client {
        mempool_t *pool;
@@ -50,16 +48,17 @@ static struct kmem_cache *_dm_io_cache;
 struct dm_io_client *dm_io_client_create(void)
 {
        struct dm_io_client *client;
+       unsigned min_ios = dm_get_reserved_bio_based_ios();
 
        client = kmalloc(sizeof(*client), GFP_KERNEL);
        if (!client)
                return ERR_PTR(-ENOMEM);
 
-       client->pool = mempool_create_slab_pool(MIN_IOS, _dm_io_cache);
+       client->pool = mempool_create_slab_pool(min_ios, _dm_io_cache);
        if (!client->pool)
                goto bad;
 
-       client->bios = bioset_create(MIN_BIOS, 0);
+       client->bios = bioset_create(min_ios, 0);
        if (!client->bios)
                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 b759a127f9c3718bbfffe2d16ca258fe4afe15e2..de570a55876451a0326d071da4cf68fd772eec2e 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/device-mapper.h>
 
+#include "dm.h"
 #include "dm-path-selector.h"
 #include "dm-uevent.h"
 
@@ -116,8 +117,6 @@ struct dm_mpath_io {
 
 typedef int (*action_fn) (struct pgpath *pgpath);
 
-#define MIN_IOS 256    /* Mempool size */
-
 static struct kmem_cache *_mpio_cache;
 
 static struct workqueue_struct *kmultipathd, *kmpath_handlerd;
@@ -190,6 +189,7 @@ static void free_priority_group(struct priority_group *pg,
 static struct multipath *alloc_multipath(struct dm_target *ti)
 {
        struct multipath *m;
+       unsigned min_ios = dm_get_reserved_rq_based_ios();
 
        m = kzalloc(sizeof(*m), GFP_KERNEL);
        if (m) {
@@ -202,7 +202,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti)
                INIT_WORK(&m->trigger_event, trigger_event);
                init_waitqueue_head(&m->pg_init_wait);
                mutex_init(&m->work_mutex);
-               m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache);
+               m->mpio_pool = mempool_create_slab_pool(min_ios, _mpio_cache);
                if (!m->mpio_pool) {
                        kfree(m);
                        return NULL;
@@ -1268,6 +1268,7 @@ static int noretry_error(int error)
        case -EREMOTEIO:
        case -EILSEQ:
        case -ENODATA:
+       case -ENOSPC:
                return 1;
        }
 
@@ -1298,8 +1299,17 @@ static int do_end_io(struct multipath *m, struct request *clone,
        if (!error && !clone->errors)
                return 0;       /* I/O complete */
 
-       if (noretry_error(error))
+       if (noretry_error(error)) {
+               if ((clone->cmd_flags & REQ_WRITE_SAME) &&
+                   !clone->q->limits.max_write_same_sectors) {
+                       struct queue_limits *limits;
+
+                       /* device doesn't really support WRITE SAME, disable it */
+                       limits = dm_get_queue_limits(dm_table_get_md(m->ti->table));
+                       limits->max_write_same_sectors = 0;
+               }
                return error;
+       }
 
        if (mpio->pgpath)
                fail_path(mpio->pgpath);
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;
index 3ac415675b6c778b5dd22aaaf4ee6c2dc4ca48eb..2d2b1b7588d7e476b7fc814a63c82bad2edb1ed6 100644 (file)
@@ -256,7 +256,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw,
         */
        INIT_WORK_ONSTACK(&req.work, do_metadata);
        queue_work(ps->metadata_wq, &req.work);
-       flush_work(&req.work);
+       flush_workqueue(ps->metadata_wq);
 
        return req.result;
 }
@@ -269,6 +269,14 @@ static chunk_t area_location(struct pstore *ps, chunk_t area)
        return NUM_SNAPSHOT_HDR_CHUNKS + ((ps->exceptions_per_area + 1) * area);
 }
 
+static void skip_metadata(struct pstore *ps)
+{
+       uint32_t stride = ps->exceptions_per_area + 1;
+       chunk_t next_free = ps->next_free;
+       if (sector_div(next_free, stride) == NUM_SNAPSHOT_HDR_CHUNKS)
+               ps->next_free++;
+}
+
 /*
  * Read or write a metadata area.  Remembering to skip the first
  * chunk which holds the header.
@@ -502,6 +510,8 @@ static int read_exceptions(struct pstore *ps,
 
        ps->current_area--;
 
+       skip_metadata(ps);
+
        return 0;
 }
 
@@ -616,8 +626,6 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
                                        struct dm_exception *e)
 {
        struct pstore *ps = get_info(store);
-       uint32_t stride;
-       chunk_t next_free;
        sector_t size = get_dev_size(dm_snap_cow(store->snap)->bdev);
 
        /* Is there enough room ? */
@@ -630,10 +638,8 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
         * Move onto the next free pending, making sure to take
         * into account the location of the metadata chunks.
         */
-       stride = (ps->exceptions_per_area + 1);
-       next_free = ++ps->next_free;
-       if (sector_div(next_free, stride) == 1)
-               ps->next_free++;
+       ps->next_free++;
+       skip_metadata(ps);
 
        atomic_inc(&ps->pending_count);
        return 0;
index c434e5aab2dfc9e6a63ca7700e5ac1c1deacd025..aec57d76db5d616c8e692fa95cee58a8f62a0573 100644 (file)
@@ -725,17 +725,16 @@ static int calc_max_buckets(void)
  */
 static int init_hash_tables(struct dm_snapshot *s)
 {
-       sector_t hash_size, cow_dev_size, origin_dev_size, max_buckets;
+       sector_t hash_size, cow_dev_size, max_buckets;
 
        /*
         * Calculate based on the size of the original volume or
         * the COW volume...
         */
        cow_dev_size = get_dev_size(s->cow->bdev);
-       origin_dev_size = get_dev_size(s->origin->bdev);
        max_buckets = calc_max_buckets();
 
-       hash_size = min(origin_dev_size, cow_dev_size) >> s->store->chunk_shift;
+       hash_size = cow_dev_size >> s->store->chunk_shift;
        hash_size = min(hash_size, max_buckets);
 
        if (hash_size < 64)
diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c
new file mode 100644 (file)
index 0000000..3d404c1
--- /dev/null
@@ -0,0 +1,980 @@
+#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_save/restore
+        * instead of preempt_disable/enable.
+        *
+        * preempt_disable/enable is racy if the driver finishes bios
+        * from non-interrupt context as well as from interrupt context
+        * or from more different interrupts.
+        *
+        * On 64-bit architectures the race only results in not counting some
+        * events, so it is acceptable.  On 32-bit architectures the race could
+        * cause the counter going off by 2^32, so we need to do proper locking
+        * there.
+        *
+        * part_stat_lock()/part_stat_unlock() have this race too.
+        */
+#if BITS_PER_LONG == 32
+       unsigned long flags;
+       local_irq_save(flags);
+#else
+       preempt_disable();
+#endif
+       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;
+       }
+
+#if BITS_PER_LONG == 32
+       local_irq_restore(flags);
+#else
+       preempt_enable();
+#endif
+}
+
+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..2c0cf511ec2385fa5a558b5d2e1e1ed0c874c9f6 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);
@@ -2083,6 +2095,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
         * them down to the data device.  The thin device's discard
         * processing will cause mappings to be removed from the btree.
         */
+       ti->discard_zeroes_data_unsupported = true;
        if (pf.discard_enabled && pf.discard_passdown) {
                ti->num_discard_bios = 1;
 
@@ -2092,7 +2105,6 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
                 * thin devices' discard limits consistent).
                 */
                ti->discards_supported = true;
-               ti->discard_zeroes_data_unsupported = true;
        }
        ti->private = pt;
 
@@ -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,17 +2672,33 @@ 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.
         * They get transferred to the live pool in bind_control_target()
         * called from pool_preresume().
         */
-       if (!pt->adjusted_pf.discard_enabled)
+       if (!pt->adjusted_pf.discard_enabled) {
+               /*
+                * Must explicitly disallow stacking discard limits otherwise the
+                * block layer will stack them if pool's data device has support.
+                * QUEUE_FLAG_DISCARD wouldn't be set but there is no way for the
+                * user to see that, so make sure to set all discard limits to 0.
+                */
+               limits->discard_granularity = 0;
                return;
+       }
 
        disable_passdown_if_not_supported(pt);
 
@@ -2669,7 +2709,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,
@@ -2794,10 +2834,10 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
        ti->per_bio_data_size = sizeof(struct dm_thin_endio_hook);
 
        /* In case the pool supports discards, pass them on. */
+       ti->discard_zeroes_data_unsupported = true;
        if (tc->pool->pf.discard_enabled) {
                ti->discards_supported = true;
                ti->num_discard_bios = 1;
-               ti->discard_zeroes_data_unsupported = true;
                /* Discard bios must be split on a block boundary */
                ti->split_discard_bios = true;
        }
@@ -2956,7 +2996,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..b3e26c7d141771c74d24726f8b5a56ea2134b156 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;
 };
 
 /*
@@ -208,10 +211,55 @@ struct dm_md_mempools {
        struct bio_set *bs;
 };
 
-#define MIN_IOS 256
+#define RESERVED_BIO_BASED_IOS         16
+#define RESERVED_REQUEST_BASED_IOS     256
+#define RESERVED_MAX_IOS               1024
 static struct kmem_cache *_io_cache;
 static struct kmem_cache *_rq_tio_cache;
 
+/*
+ * Bio-based DM's mempools' reserved IOs set by the user.
+ */
+static unsigned reserved_bio_based_ios = RESERVED_BIO_BASED_IOS;
+
+/*
+ * Request-based DM's mempools' reserved IOs set by the user.
+ */
+static unsigned reserved_rq_based_ios = RESERVED_REQUEST_BASED_IOS;
+
+static unsigned __dm_get_reserved_ios(unsigned *reserved_ios,
+                                     unsigned def, unsigned max)
+{
+       unsigned ios = ACCESS_ONCE(*reserved_ios);
+       unsigned modified_ios = 0;
+
+       if (!ios)
+               modified_ios = def;
+       else if (ios > max)
+               modified_ios = max;
+
+       if (modified_ios) {
+               (void)cmpxchg(reserved_ios, ios, modified_ios);
+               ios = modified_ios;
+       }
+
+       return ios;
+}
+
+unsigned dm_get_reserved_bio_based_ios(void)
+{
+       return __dm_get_reserved_ios(&reserved_bio_based_ios,
+                                    RESERVED_BIO_BASED_IOS, RESERVED_MAX_IOS);
+}
+EXPORT_SYMBOL_GPL(dm_get_reserved_bio_based_ios);
+
+unsigned dm_get_reserved_rq_based_ios(void)
+{
+       return __dm_get_reserved_ios(&reserved_rq_based_ios,
+                                    RESERVED_REQUEST_BASED_IOS, RESERVED_MAX_IOS);
+}
+EXPORT_SYMBOL_GPL(dm_get_reserved_rq_based_ios);
+
 static int __init local_init(void)
 {
        int r = -ENOMEM;
@@ -269,6 +317,7 @@ static int (*_inits[])(void) __initdata = {
        dm_io_init,
        dm_kcopyd_init,
        dm_interface_init,
+       dm_statistics_init,
 };
 
 static void (*_exits[])(void) = {
@@ -279,6 +328,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 +434,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 +526,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 +537,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 +556,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 +1588,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 +2015,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 +2027,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 +2080,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 +2222,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 +2307,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;
 }
 
@@ -2249,6 +2322,17 @@ struct target_type *dm_get_immutable_target_type(struct mapped_device *md)
        return md->immutable_target_type;
 }
 
+/*
+ * The queue_limits are only valid as long as you have a reference
+ * count on 'md'.
+ */
+struct queue_limits *dm_get_queue_limits(struct mapped_device *md)
+{
+       BUG_ON(!atomic_read(&md->holders));
+       return &md->queue->limits;
+}
+EXPORT_SYMBOL_GPL(dm_get_queue_limits);
+
 /*
  * Fully initialize a request-based queue (->elevator, ->request_fn, etc).
  */
@@ -2695,6 +2779,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.
  *---------------------------------------------------------------*/
@@ -2802,18 +2918,18 @@ struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity, u
 
        if (type == DM_TYPE_BIO_BASED) {
                cachep = _io_cache;
-               pool_size = 16;
+               pool_size = dm_get_reserved_bio_based_ios();
                front_pad = roundup(per_bio_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone);
        } else if (type == DM_TYPE_REQUEST_BASED) {
                cachep = _rq_tio_cache;
-               pool_size = MIN_IOS;
+               pool_size = dm_get_reserved_rq_based_ios();
                front_pad = offsetof(struct dm_rq_clone_bio_info, clone);
                /* per_bio_data_size is not used. See __bind_mempools(). */
                WARN_ON(per_bio_data_size != 0);
        } else
                goto out;
 
-       pools->io_pool = mempool_create_slab_pool(MIN_IOS, cachep);
+       pools->io_pool = mempool_create_slab_pool(pool_size, cachep);
        if (!pools->io_pool)
                goto out;
 
@@ -2864,6 +2980,13 @@ module_exit(dm_exit);
 
 module_param(major, uint, 0);
 MODULE_PARM_DESC(major, "The major number of the device mapper");
+
+module_param(reserved_bio_based_ios, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(reserved_bio_based_ios, "Reserved IOs in bio-based mempools");
+
+module_param(reserved_rq_based_ios, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(reserved_rq_based_ios, "Reserved IOs in request-based mempools");
+
 MODULE_DESCRIPTION(DM_NAME " driver");
 MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
 MODULE_LICENSE("GPL");
index 45b97da1bd061f02a32e0e7523fdf5125ffb1089..1d1ad7b7e527e671d1265007b25e2e04217509ab 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,15 @@ 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
+ */
+unsigned dm_get_reserved_bio_based_ios(void);
+unsigned dm_get_reserved_rq_based_ios(void);
+
+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 d0fdc134068a05ed9967fe98ca7d9a6d6429e710..f6ff711aa5bbbaa4a177dbd416ccdab53017bb23 100644 (file)
@@ -57,6 +57,7 @@ void mei_amthif_reset_params(struct mei_device *dev)
        dev->iamthif_ioctl = false;
        dev->iamthif_state = MEI_IAMTHIF_IDLE;
        dev->iamthif_timer = 0;
+       dev->iamthif_stall_timer = 0;
 }
 
 /**
index 6d0282c08a06cdbe6233a379ee575882b1d7a525..cd2033cd7120d7631fa8d345409ed9ea86259799 100644 (file)
@@ -297,10 +297,13 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
 
        if (cl->reading_state != MEI_READ_COMPLETE &&
            !waitqueue_active(&cl->rx_wait)) {
+
                mutex_unlock(&dev->device_lock);
 
                if (wait_event_interruptible(cl->rx_wait,
-                               (MEI_READ_COMPLETE == cl->reading_state))) {
+                               cl->reading_state == MEI_READ_COMPLETE  ||
+                               mei_cl_is_transitioning(cl))) {
+
                        if (signal_pending(current))
                                return -EINTR;
                        return -ERESTARTSYS;
index 9eb031e920701e8ad8feadf3bec2900b182e4a5c..892cc4207fa202629e27698c0ae536f0b81880b0 100644 (file)
@@ -90,6 +90,12 @@ static inline bool mei_cl_is_connected(struct mei_cl *cl)
                cl->dev->dev_state == MEI_DEV_ENABLED &&
                cl->state == MEI_FILE_CONNECTED);
 }
+static inline bool mei_cl_is_transitioning(struct mei_cl *cl)
+{
+       return (MEI_FILE_INITIALIZING == cl->state ||
+               MEI_FILE_DISCONNECTED == cl->state ||
+               MEI_FILE_DISCONNECTING == cl->state);
+}
 
 bool mei_cl_is_other_connecting(struct mei_cl *cl);
 int mei_cl_disconnect(struct mei_cl *cl);
index 6127ab64bb399323e57e418e9742c2f5b8a9d86d..0a0448326e9d583f951932b220d90186c59f92b7 100644 (file)
@@ -35,11 +35,15 @@ static void mei_hbm_me_cl_allocate(struct mei_device *dev)
        struct mei_me_client *clients;
        int b;
 
+       dev->me_clients_num = 0;
+       dev->me_client_presentation_num = 0;
+       dev->me_client_index = 0;
+
        /* count how many ME clients we have */
        for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
                dev->me_clients_num++;
 
-       if (dev->me_clients_num <= 0)
+       if (dev->me_clients_num == 0)
                return;
 
        kfree(dev->me_clients);
@@ -221,7 +225,7 @@ static int mei_hbm_prop_req(struct mei_device *dev)
        struct hbm_props_request *prop_req;
        const size_t len = sizeof(struct hbm_props_request);
        unsigned long next_client_index;
-       u8 client_num;
+       unsigned long client_num;
 
 
        client_num = dev->me_client_presentation_num;
@@ -677,8 +681,6 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
                if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
                    dev->hbm_state == MEI_HBM_ENUM_CLIENTS) {
                                dev->init_clients_timer = 0;
-                               dev->me_client_presentation_num = 0;
-                               dev->me_client_index = 0;
                                mei_hbm_me_cl_allocate(dev);
                                dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
 
index 92c73118b13c450149e21ec48b990e6329f4e5b1..6197018e2f16a24296619442fe6c8744c7c55b88 100644 (file)
@@ -175,6 +175,9 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
                memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg));
        }
 
+       /* we're already in reset, cancel the init timer */
+       dev->init_clients_timer = 0;
+
        dev->me_clients_num = 0;
        dev->rd_msg_hdr = 0;
        dev->wd_pending = false;
index 173ff095be0dd6747145c9653726b3e00f85cd81..cabeddd66c1f406f73f7e5bed2a56b7e52cd7621 100644 (file)
@@ -249,19 +249,16 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
                mutex_unlock(&dev->device_lock);
 
                if (wait_event_interruptible(cl->rx_wait,
-                       (MEI_READ_COMPLETE == cl->reading_state ||
-                        MEI_FILE_INITIALIZING == cl->state ||
-                        MEI_FILE_DISCONNECTED == cl->state ||
-                        MEI_FILE_DISCONNECTING == cl->state))) {
+                               MEI_READ_COMPLETE == cl->reading_state ||
+                               mei_cl_is_transitioning(cl))) {
+
                        if (signal_pending(current))
                                return -EINTR;
                        return -ERESTARTSYS;
                }
 
                mutex_lock(&dev->device_lock);
-               if (MEI_FILE_INITIALIZING == cl->state ||
-                   MEI_FILE_DISCONNECTED == cl->state ||
-                   MEI_FILE_DISCONNECTING == cl->state) {
+               if (mei_cl_is_transitioning(cl)) {
                        rets = -EBUSY;
                        goto out;
                }
index 7b918b2fb89468ad6c653a3ff9e0f616aefa5022..456b322013e269fc61f911d6f5761768c2863d4f 100644 (file)
@@ -396,9 +396,9 @@ struct mei_device {
        struct mei_me_client *me_clients; /* Note: memory has to be allocated */
        DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX);
        DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX);
-       u8 me_clients_num;
-       u8 me_client_presentation_num;
-       u8 me_client_index;
+       unsigned long me_clients_num;
+       unsigned long me_client_presentation_num;
+       unsigned long me_client_index;
 
        struct mei_cl wd_cl;
        enum mei_wd_states wd_state;
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..f344659dceac2739f47e032cbaaec2c54c86b6f6 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;
@@ -127,9 +113,14 @@ 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,r8a7740-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-shmobile" },
+       { .compatible = "renesas,sdhi-sh7372" },
+       { .compatible = "renesas,sdhi-sh73a0", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a7778", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a7779", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a7790", .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..6bc9618af0942528d67e7846810adf7c2288b75a 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;
 };
@@ -159,11 +168,25 @@ static inline int write_disable(struct m25p *flash)
  */
 static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
 {
+       int status;
+       bool need_wren = false;
+
        switch (JEDEC_MFR(jedec_id)) {
+       case CFI_MFR_ST: /* Micron, actually */
+               /* Some Micron need WREN command; all will accept it */
+               need_wren = true;
        case CFI_MFR_MACRONIX:
        case 0xEF /* winbond */:
+               if (need_wren)
+                       write_enable(flash);
+
                flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
-               return spi_write(flash->spi, flash->command, 1);
+               status = spi_write(flash->spi, flash->command, 1);
+
+               if (need_wren)
+                       write_disable(flash);
+
+               return status;
        default:
                /* Spansion style */
                flash->command[0] = OPCODE_BRWR;
@@ -371,7 +394,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 +445,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 +705,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 +719,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 +757,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 +788,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 +871,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 +952,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 +1004,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 +1046,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 +1063,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 +1132,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..d340b2f198c614b72fc68eed945a8c1a662d147c 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,76 @@ 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)
+               return -ENOMEM;
+
+       /* 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");
+       ret = 0;
+
+ext_out:
+       kfree(ep);
+       return ret;
+}
+
 /*
  * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
  */
@@ -2907,9 +2986,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 +3187,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 +3289,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 +3565,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 +3787,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..dd03dfdfb0d65e0ded1b0a124221663b586482b5 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,47 @@ 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)
 {
@@ -1237,12 +1283,6 @@ static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
 
        return 0;
 }
-#else
-static inline int pxa3xx_nand_probe_dt(struct platform_device *pdev)
-{
-       return 0;
-}
-#endif
 
 static int pxa3xx_nand_probe(struct platform_device *pdev)
 {
@@ -1251,11 +1291,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 +1315,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 +1330,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 +1353,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 +1374,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_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);
similarity index 93%
rename from drivers/mtd/tests/mtd_nandbiterrs.c
rename to drivers/mtd/tests/nandbiterrs.c
index 207bf9a9972f3ee400412a1bb40ea4e06cc19745..3cd3aabbe1cd8bd3a92a1131e4955c83c41d4431 100644 (file)
@@ -49,6 +49,7 @@
 #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);
@@ -98,47 +99,13 @@ static uint8_t hash(unsigned offset)
        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;
+       return mtdtest_write(mtd, offset, mtd->writesize, wbuffer);
 }
 
 /* Re-writes the data area while leaving the OOB alone. */
@@ -415,7 +382,7 @@ static int __init mtd_nandbiterrs_init(void)
                goto exit_rbuffer;
        }
 
-       err = erase_block();
+       err = mtdtest_erase_eraseblock(mtd, eraseblock);
        if (err)
                goto exit_error;
 
@@ -428,7 +395,7 @@ static int __init mtd_nandbiterrs_init(void)
                goto exit_error;
 
        /* We leave the block un-erased in case of test failure. */
-       err = erase_block();
+       err = mtdtest_erase_eraseblock(mtd, eraseblock);
        if (err)
                goto exit_error;
 
similarity index 90%
rename from drivers/mtd/tests/mtd_oobtest.c
rename to drivers/mtd/tests/oobtest.c
index 3e24b379ffa42e8564df4e0be373ef2fe6aa21a5..ff35c465bfeea5cb4f8598d95e05993c8cc590db 100644 (file)
@@ -31,6 +31,8 @@
 #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");
@@ -49,49 +51,6 @@ 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;
@@ -304,38 +263,6 @@ static int verify_all_eraseblocks(void)
        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;
@@ -380,17 +307,16 @@ static int __init mtd_oobtest_init(void)
 
        err = -ENOMEM;
        readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!readbuf) {
-               pr_err("error: cannot allocate memory\n");
+       if (!readbuf)
                goto out;
-       }
        writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!writebuf) {
-               pr_err("error: cannot allocate memory\n");
+       if (!writebuf)
+               goto out;
+       bbt = kzalloc(ebcnt, GFP_KERNEL);
+       if (!bbt)
                goto out;
-       }
 
-       err = scan_for_bad_eraseblocks();
+       err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
@@ -402,7 +328,7 @@ static int __init mtd_oobtest_init(void)
        /* First test: write all OOB, read it back and verify */
        pr_info("test 1 of 5\n");
 
-       err = erase_whole_device();
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
@@ -422,7 +348,7 @@ static int __init mtd_oobtest_init(void)
         */
        pr_info("test 2 of 5\n");
 
-       err = erase_whole_device();
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
@@ -452,7 +378,7 @@ static int __init mtd_oobtest_init(void)
         */
        pr_info("test 3 of 5\n");
 
-       err = erase_whole_device();
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
@@ -485,7 +411,7 @@ static int __init mtd_oobtest_init(void)
        /* Fourth test: try to write off end of device */
        pr_info("test 4 of 5\n");
 
-       err = erase_whole_device();
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
@@ -577,7 +503,7 @@ static int __init mtd_oobtest_init(void)
                        errcnt += 1;
                }
 
-               err = erase_eraseblock(ebcnt - 1);
+               err = mtdtest_erase_eraseblock(mtd, ebcnt - 1);
                if (err)
                        goto out;
 
@@ -626,7 +552,7 @@ static int __init mtd_oobtest_init(void)
        pr_info("test 5 of 5\n");
 
        /* Erase all eraseblocks */
-       err = erase_whole_device();
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
similarity index 63%
rename from drivers/mtd/tests/mtd_pagetest.c
rename to drivers/mtd/tests/pagetest.c
index 0c1140b6c2863b92087d1b8156895a5a5162e664..44b96e999ad4694c5ad222c357d98bc22c27c247 100644 (file)
@@ -31,6 +31,8 @@
 #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");
@@ -48,52 +50,18 @@ 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;
+       return mtdtest_write(mtd, addr, mtd->erasesize, writebuf);
 }
 
 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;
@@ -109,31 +77,16 @@ static int verify_eraseblock(int ebnum)
        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);
+               err = mtdtest_read(mtd, addr0, bufsize, twopages);
+               if (err)
                        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));
+               err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
+               if (err)
                        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);
+               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);
@@ -145,31 +98,16 @@ static int verify_eraseblock(int ebnum)
                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);
+               err = mtdtest_read(mtd, addr0, bufsize, twopages);
+               if (err)
                        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));
+               err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
+               if (err)
                        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);
+               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)) {
@@ -184,17 +122,14 @@ static int verify_eraseblock(int ebnum)
 
 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");
+       if (!pp1)
                return -ENOMEM;
-       }
        pp2 = pp1 + pgsize;
        pp3 = pp2 + pgsize;
        pp4 = pp3 + pgsize;
@@ -210,24 +145,16 @@ static int crosstest(void)
 
        /* 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);
+       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 = 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);
+       err = mtdtest_read(mtd, addr, pgsize, pp1);
+       if (err) {
                kfree(pp1);
                return err;
        }
@@ -235,12 +162,8 @@ static int crosstest(void)
        /* 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);
+       err = mtdtest_read(mtd, addr, pgsize, pp2);
+       if (err) {
                kfree(pp1);
                return err;
        }
@@ -248,12 +171,8 @@ static int crosstest(void)
        /* 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);
+       err = mtdtest_read(mtd, addr, pgsize, pp3);
+       if (err) {
                kfree(pp1);
                return err;
        }
@@ -261,12 +180,8 @@ static int crosstest(void)
        /* 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);
+       err = mtdtest_read(mtd, addr, pgsize, pp4);
+       if (err) {
                kfree(pp1);
                return err;
        }
@@ -285,7 +200,6 @@ static int crosstest(void)
 
 static int erasecrosstest(void)
 {
-       size_t read, written;
        int err = 0, i, ebnum, ebnum2;
        loff_t addr0;
        char *readbuf = twopages;
@@ -304,30 +218,22 @@ static int erasecrosstest(void)
                ebnum2 -= 1;
 
        pr_info("erasing block %d\n", ebnum);
-       err = erase_eraseblock(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 = 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;
-       }
+       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 = 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;
-       }
+       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)) {
@@ -337,35 +243,27 @@ static int erasecrosstest(void)
        }
 
        pr_info("erasing block %d\n", ebnum);
-       err = erase_eraseblock(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 = 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;
-       }
+       err = mtdtest_write(mtd, addr0, pgsize, writebuf);
+       if (err)
+               return err;
 
        pr_info("erasing block %d\n", ebnum2);
-       err = erase_eraseblock(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 = 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;
-       }
+       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)) {
@@ -381,7 +279,6 @@ static int erasecrosstest(void)
 
 static int erasetest(void)
 {
-       size_t read, written;
        int err = 0, i, ebnum, ok = 1;
        loff_t addr0;
 
@@ -395,33 +292,25 @@ static int erasetest(void)
        }
 
        pr_info("erasing block %d\n", ebnum);
-       err = erase_eraseblock(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 = 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;
-       }
+       err = mtdtest_write(mtd, addr0, pgsize, writebuf);
+       if (err)
+               return err;
 
        pr_info("erasing block %d\n", ebnum);
-       err = erase_eraseblock(ebnum);
+       err = mtdtest_erase_eraseblock(mtd, 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;
-       }
+       err = mtdtest_read(mtd, addr0, pgsize, twopages);
+       if (err)
+               return err;
 
        pr_info("verifying 1st page of block %d is all 0xff\n",
               ebnum);
@@ -440,38 +329,6 @@ static int erasetest(void)
        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;
@@ -516,36 +373,28 @@ static int __init mtd_pagetest_init(void)
        err = -ENOMEM;
        bufsize = pgsize * 2;
        writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!writebuf) {
-               pr_err("error: cannot allocate memory\n");
+       if (!writebuf)
                goto out;
-       }
        twopages = kmalloc(bufsize, GFP_KERNEL);
-       if (!twopages) {
-               pr_err("error: cannot allocate memory\n");
+       if (!twopages)
                goto out;
-       }
        boundary = kmalloc(bufsize, GFP_KERNEL);
-       if (!boundary) {
-               pr_err("error: cannot allocate memory\n");
+       if (!boundary)
                goto out;
-       }
 
-       err = scan_for_bad_eraseblocks();
+       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");
-       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);
+       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);
similarity index 83%
rename from drivers/mtd/tests/mtd_readtest.c
rename to drivers/mtd/tests/readtest.c
index 266de04b6d29ef1666ab54ea05250411536ed0ef..626e66d0f7e7a081271cae6c88f608edc8be8727 100644 (file)
@@ -29,6 +29,8 @@
 #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");
@@ -44,7 +46,6 @@ 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;
@@ -52,16 +53,10 @@ static int read_eraseblock_by_page(int ebnum)
 
        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);
+               ret = mtdtest_read(mtd, addr, pgsize, buf);
+               if (ret) {
                        if (!err)
                                err = ret;
-                       if (!err)
-                               err = -EINVAL;
                }
                if (mtd->oobsize) {
                        struct mtd_oob_ops ops;
@@ -127,41 +122,6 @@ static void dump_eraseblock(int ebnum)
                }
 }
 
-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;
@@ -204,17 +164,16 @@ static int __init mtd_readtest_init(void)
 
        err = -ENOMEM;
        iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!iobuf) {
-               pr_err("error: cannot allocate memory\n");
+       if (!iobuf)
                goto out;
-       }
        iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!iobuf1) {
-               pr_err("error: cannot allocate memory\n");
+       if (!iobuf1)
                goto out;
-       }
 
-       err = scan_for_bad_eraseblocks();
+       bbt = kzalloc(ebcnt, GFP_KERNEL);
+       if (!bbt)
+               goto out;
+       err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
similarity index 69%
rename from drivers/mtd/tests/mtd_speedtest.c
rename to drivers/mtd/tests/speedtest.c
index a6ce9c1fa6c56c2cfcbc345e7fd53d323b7b7cbf..87ff6a29f84ee94bacc657aaf6f52700aa45074d 100644 (file)
@@ -30,6 +30,8 @@
 #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");
@@ -49,33 +51,6 @@ 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;
@@ -103,54 +78,23 @@ static int multiblock_erase(int ebnum, int blocks)
        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;
+       return mtdtest_write(mtd, addr, mtd->erasesize, iobuf);
 }
 
 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;
+               err = mtdtest_write(mtd, addr, pgsize, buf);
+               if (err)
                        break;
-               }
                addr += pgsize;
                buf += pgsize;
        }
@@ -160,74 +104,41 @@ static int write_eraseblock_by_page(int ebnum)
 
 static int write_eraseblock_by_2pages(int ebnum)
 {
-       size_t written, sz = pgsize * 2;
+       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 = mtd_write(mtd, addr, sz, &written, buf);
-               if (err || written != sz) {
-                       pr_err("error: write failed at %#llx\n",
-                              addr);
-                       if (!err)
-                               err = -EINVAL;
+               err = mtdtest_write(mtd, addr, sz, buf);
+               if (err)
                        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;
-               }
-       }
+       if (pgcnt % 2)
+               err = mtdtest_write(mtd, addr, pgsize, buf);
 
        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;
+       return mtdtest_read(mtd, addr, mtd->erasesize, iobuf);
 }
 
 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;
+               err = mtdtest_read(mtd, addr, pgsize, buf);
+               if (err)
                        break;
-               }
                addr += pgsize;
                buf += pgsize;
        }
@@ -237,53 +148,24 @@ static int read_eraseblock_by_page(int ebnum)
 
 static int read_eraseblock_by_2pages(int ebnum)
 {
-       size_t read, sz = pgsize * 2;
+       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 = 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;
+               err = mtdtest_read(mtd, addr, sz, buf);
+               if (err)
                        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;
-               }
-       }
+       if (pgcnt % 2)
+               err = mtdtest_read(mtd, addr, pgsize, buf);
 
        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);
@@ -308,32 +190,6 @@ static long calc_speed(void)
        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;
@@ -384,18 +240,23 @@ static int __init mtd_speedtest_init(void)
 
        err = -ENOMEM;
        iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!iobuf) {
-               pr_err("error: cannot allocate memory\n");
+       if (!iobuf)
                goto out;
-       }
 
        prandom_bytes(iobuf, mtd->erasesize);
 
-       err = scan_for_bad_eraseblocks();
+       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 = erase_whole_device();
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
@@ -429,7 +290,7 @@ static int __init mtd_speedtest_init(void)
        speed = calc_speed();
        pr_info("eraseblock read speed is %ld KiB/s\n", speed);
 
-       err = erase_whole_device();
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
@@ -463,7 +324,7 @@ static int __init mtd_speedtest_init(void)
        speed = calc_speed();
        pr_info("page read speed is %ld KiB/s\n", speed);
 
-       err = erase_whole_device();
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
@@ -500,14 +361,9 @@ static int __init mtd_speedtest_init(void)
        /* 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();
-       }
+       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);
similarity index 74%
rename from drivers/mtd/tests/mtd_stresstest.c
rename to drivers/mtd/tests/stresstest.c
index 787f539d16ca436099826f0626bb4c57efe6da6d..c9d42cc2df1b5303804217f7621af9539cffc28f 100644 (file)
@@ -31,6 +31,8 @@
 #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");
@@ -81,49 +83,11 @@ static int rand_len(int 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;
+       int len = rand_len(offs);
        loff_t addr;
 
        if (bbt[eb + 1]) {
@@ -133,28 +97,17 @@ static int do_read(void)
                        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;
+       return mtdtest_read(mtd, addr, len, readbuf);
 }
 
 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);
+               err = mtdtest_erase_eraseblock(mtd, eb);
                if (err)
                        return err;
                offs = offsets[eb] = 0;
@@ -165,21 +118,16 @@ static int do_write(void)
                if (bbt[eb + 1])
                        len = mtd->erasesize - offs;
                else {
-                       err = erase_eraseblock(eb + 1);
+                       err = mtdtest_erase_eraseblock(mtd, 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;
+       err = mtdtest_write(mtd, addr, len, writebuf);
+       if (unlikely(err))
                return err;
-       }
        offs += len;
        while (offs > mtd->erasesize) {
                offsets[eb++] = mtd->erasesize;
@@ -197,30 +145,6 @@ static int do_operation(void)
                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;
@@ -276,15 +200,16 @@ static int __init mtd_stresstest_init(void)
        readbuf = vmalloc(bufsize);
        writebuf = vmalloc(bufsize);
        offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL);
-       if (!readbuf || !writebuf || !offsets) {
-               pr_err("error: cannot allocate memory\n");
+       if (!readbuf || !writebuf || !offsets)
                goto out;
-       }
        for (i = 0; i < ebcnt; i++)
                offsets[i] = mtd->erasesize;
        prandom_bytes(writebuf, bufsize);
 
-       err = scan_for_bad_eraseblocks();
+       bbt = kzalloc(ebcnt, GFP_KERNEL);
+       if (!bbt)
+               goto out;
+       err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
similarity index 86%
rename from drivers/mtd/tests/mtd_subpagetest.c
rename to drivers/mtd/tests/subpagetest.c
index aade56f2794541f9d0545be12a0110f9ffe18ea1..e2c0adf24cfc35aa6692ff5267b93babc523c69c 100644 (file)
@@ -30,6 +30,8 @@
 #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");
@@ -51,50 +53,6 @@ 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;
@@ -317,38 +275,6 @@ static int verify_all_eraseblocks_ff(void)
        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;
@@ -393,21 +319,20 @@ static int __init mtd_subpagetest_init(void)
        err = -ENOMEM;
        bufsize = subpgsize * 32;
        writebuf = kmalloc(bufsize, GFP_KERNEL);
-       if (!writebuf) {
-               pr_info("error: cannot allocate memory\n");
+       if (!writebuf)
                goto out;
-       }
        readbuf = kmalloc(bufsize, GFP_KERNEL);
-       if (!readbuf) {
-               pr_info("error: cannot allocate memory\n");
+       if (!readbuf)
+               goto out;
+       bbt = kzalloc(ebcnt, GFP_KERNEL);
+       if (!bbt)
                goto out;
-       }
 
-       err = scan_for_bad_eraseblocks();
+       err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
-       err = erase_whole_device();
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
@@ -439,7 +364,7 @@ static int __init mtd_subpagetest_init(void)
        }
        pr_info("verified %u eraseblocks\n", i);
 
-       err = erase_whole_device();
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
@@ -477,7 +402,7 @@ static int __init mtd_subpagetest_init(void)
        }
        pr_info("verified %u eraseblocks\n", i);
 
-       err = erase_whole_device();
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
        if (err)
                goto out;
 
similarity index 90%
rename from drivers/mtd/tests/mtd_torturetest.c
rename to drivers/mtd/tests/torturetest.c
index 3a9f6a6a79f99d4c5662ab3fc90051a23e2ffbed..eeab96973cf07e6dcab864c5ee4e23eff0f0a32c 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include "mtd_test.h"
 
 #define RETRIES 3
 
@@ -92,35 +93,6 @@ 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.
@@ -208,7 +180,7 @@ static inline int write_pattern(int ebnum, void *buf)
 static int __init tort_init(void)
 {
        int err = 0, i, infinite = !cycles_count;
-       int *bad_ebs;
+       unsigned char *bad_ebs;
 
        printk(KERN_INFO "\n");
        printk(KERN_INFO "=================================================\n");
@@ -265,7 +237,7 @@ static int __init tort_init(void)
        if (!check_buf)
                goto out_patt_FF;
 
-       bad_ebs = kcalloc(ebcnt, sizeof(*bad_ebs), GFP_KERNEL);
+       bad_ebs = kzalloc(ebcnt, GFP_KERNEL);
        if (!bad_ebs)
                goto out_check_buf;
 
@@ -283,40 +255,16 @@ static int __init tort_init(void)
                }
        }
 
-       /*
-        * 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;
-                       }
-               }
-       }
+       err = mtdtest_scan_for_bad_eraseblocks(mtd, bad_ebs, eb, ebcnt);
+       if (err)
+               goto out;
 
        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();
-               }
+               mtdtest_erase_good_eraseblocks(mtd, bad_ebs, eb, ebcnt);
 
                /* Check if the eraseblocks contain only 0xFF bytes */
                if (check) {
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..e883bfe2e727aa1bf6fd2fb2cea2375578c8c06d 100644 (file)
@@ -1724,6 +1724,7 @@ static int __bond_release_one(struct net_device *bond_dev,
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave, *oldcurrent;
        struct sockaddr addr;
+       int old_flags = bond_dev->flags;
        netdev_features_t old_features = bond_dev->features;
 
        /* slave is not a slave or master is not master of this slave */
@@ -1855,12 +1856,18 @@ static int __bond_release_one(struct net_device *bond_dev,
         * bond_change_active_slave(..., NULL)
         */
        if (!USES_PRIMARY(bond->params.mode)) {
-               /* unset promiscuity level from slave */
-               if (bond_dev->flags & IFF_PROMISC)
+               /* unset promiscuity level from slave
+                * NOTE: The NETDEV_CHANGEADDR call above may change the value
+                * of the IFF_PROMISC flag in the bond_dev, but we need the
+                * value of that flag before that change, as that was the value
+                * when this slave was attached, so we cache at the start of the
+                * function and use it here. Same goes for ALLMULTI below
+                */
+               if (old_flags & IFF_PROMISC)
                        dev_set_promiscuity(slave_dev, -1);
 
                /* unset allmulti level from slave */
-               if (bond_dev->flags & IFF_ALLMULTI)
+               if (old_flags & IFF_ALLMULTI)
                        dev_set_allmulti(slave_dev, -1);
 
                bond_hw_addr_flush(bond_dev, slave_dev);
@@ -2404,8 +2411,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 +4423,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 71c677e651d7cbead0f673f53a93e89514e74eb3..3f21142138b79868a0f18fa7d246432e99d96192 100644 (file)
@@ -702,7 +702,6 @@ static int flexcan_chip_start(struct net_device *dev)
 {
        struct flexcan_priv *priv = netdev_priv(dev);
        struct flexcan_regs __iomem *regs = priv->base;
-       unsigned int i;
        int err;
        u32 reg_mcr, reg_ctrl;
 
@@ -772,17 +771,6 @@ static int flexcan_chip_start(struct net_device *dev)
        netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
        flexcan_write(reg_ctrl, &regs->ctrl);
 
-       for (i = 0; i < ARRAY_SIZE(regs->cantxfg); i++) {
-               flexcan_write(0, &regs->cantxfg[i].can_ctrl);
-               flexcan_write(0, &regs->cantxfg[i].can_id);
-               flexcan_write(0, &regs->cantxfg[i].data[0]);
-               flexcan_write(0, &regs->cantxfg[i].data[1]);
-
-               /* put MB into rx queue */
-               flexcan_write(FLEXCAN_MB_CNT_CODE(0x4),
-                       &regs->cantxfg[i].can_ctrl);
-       }
-
        /* acceptance mask/acceptance code (accept everything) */
        flexcan_write(0x0, &regs->rxgmask);
        flexcan_write(0x0, &regs->rx14mask);
index 874188ba06f7172fed36b93db05be06ae0e2bd59..25377e547f9b01f49167caa13f510c51fb2bd1c7 100644 (file)
@@ -76,6 +76,10 @@ MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces");
 /* maximum rx buffer len: extended CAN frame with timestamp */
 #define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r")+1)
 
+#define SLC_CMD_LEN 1
+#define SLC_SFF_ID_LEN 3
+#define SLC_EFF_ID_LEN 8
+
 struct slcan {
        int                     magic;
 
@@ -142,47 +146,63 @@ static void slc_bump(struct slcan *sl)
 {
        struct sk_buff *skb;
        struct can_frame cf;
-       int i, dlc_pos, tmp;
-       unsigned long ultmp;
-       char cmd = sl->rbuff[0];
-
-       if ((cmd != 't') && (cmd != 'T') && (cmd != 'r') && (cmd != 'R'))
+       int i, tmp;
+       u32 tmpid;
+       char *cmd = sl->rbuff;
+
+       cf.can_id = 0;
+
+       switch (*cmd) {
+       case 'r':
+               cf.can_id = CAN_RTR_FLAG;
+               /* fallthrough */
+       case 't':
+               /* store dlc ASCII value and terminate SFF CAN ID string */
+               cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN];
+               sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN] = 0;
+               /* point to payload data behind the dlc */
+               cmd += SLC_CMD_LEN + SLC_SFF_ID_LEN + 1;
+               break;
+       case 'R':
+               cf.can_id = CAN_RTR_FLAG;
+               /* fallthrough */
+       case 'T':
+               cf.can_id |= CAN_EFF_FLAG;
+               /* store dlc ASCII value and terminate EFF CAN ID string */
+               cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN];
+               sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN] = 0;
+               /* point to payload data behind the dlc */
+               cmd += SLC_CMD_LEN + SLC_EFF_ID_LEN + 1;
+               break;
+       default:
                return;
+       }
 
-       if (cmd & 0x20) /* tiny chars 'r' 't' => standard frame format */
-               dlc_pos = 4; /* dlc position tiiid */
-       else
-               dlc_pos = 9; /* dlc position Tiiiiiiiid */
-
-       if (!((sl->rbuff[dlc_pos] >= '0') && (sl->rbuff[dlc_pos] < '9')))
+       if (kstrtou32(sl->rbuff + SLC_CMD_LEN, 16, &tmpid))
                return;
 
-       cf.can_dlc = sl->rbuff[dlc_pos] - '0'; /* get can_dlc from ASCII val */
+       cf.can_id |= tmpid;
 
-       sl->rbuff[dlc_pos] = 0; /* terminate can_id string */
-
-       if (kstrtoul(sl->rbuff+1, 16, &ultmp))
+       /* get can_dlc from sanitized ASCII value */
+       if (cf.can_dlc >= '0' && cf.can_dlc < '9')
+               cf.can_dlc -= '0';
+       else
                return;
 
-       cf.can_id = ultmp;
-
-       if (!(cmd & 0x20)) /* NO tiny chars => extended frame format */
-               cf.can_id |= CAN_EFF_FLAG;
-
-       if ((cmd | 0x20) == 'r') /* RTR frame */
-               cf.can_id |= CAN_RTR_FLAG;
-
        *(u64 *) (&cf.data) = 0; /* clear payload */
 
-       for (i = 0, dlc_pos++; i < cf.can_dlc; i++) {
-               tmp = hex_to_bin(sl->rbuff[dlc_pos++]);
-               if (tmp < 0)
-                       return;
-               cf.data[i] = (tmp << 4);
-               tmp = hex_to_bin(sl->rbuff[dlc_pos++]);
-               if (tmp < 0)
-                       return;
-               cf.data[i] |= tmp;
+       /* RTR frames may have a dlc > 0 but they never have any data bytes */
+       if (!(cf.can_id & CAN_RTR_FLAG)) {
+               for (i = 0; i < cf.can_dlc; i++) {
+                       tmp = hex_to_bin(*cmd++);
+                       if (tmp < 0)
+                               return;
+                       cf.data[i] = (tmp << 4);
+                       tmp = hex_to_bin(*cmd++);
+                       if (tmp < 0)
+                               return;
+                       cf.data[i] |= tmp;
+               }
        }
 
        skb = dev_alloc_skb(sizeof(struct can_frame) +
@@ -209,7 +229,6 @@ static void slc_bump(struct slcan *sl)
 /* parse tty input stream */
 static void slcan_unesc(struct slcan *sl, unsigned char s)
 {
-
        if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */
                if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
                    (sl->rcount > 4))  {
@@ -236,27 +255,46 @@ static void slcan_unesc(struct slcan *sl, unsigned char s)
 /* Encapsulate one can_frame and stuff into a TTY queue. */
 static void slc_encaps(struct slcan *sl, struct can_frame *cf)
 {
-       int actual, idx, i;
-       char cmd;
+       int actual, i;
+       unsigned char *pos;
+       unsigned char *endpos;
+       canid_t id = cf->can_id;
+
+       pos = sl->xbuff;
 
        if (cf->can_id & CAN_RTR_FLAG)
-               cmd = 'R'; /* becomes 'r' in standard frame format */
+               *pos = 'R'; /* becomes 'r' in standard frame format (SFF) */
        else
-               cmd = 'T'; /* becomes 't' in standard frame format */
+               *pos = 'T'; /* becomes 't' in standard frame format (SSF) */
 
-       if (cf->can_id & CAN_EFF_FLAG)
-               sprintf(sl->xbuff, "%c%08X%d", cmd,
-                       cf->can_id & CAN_EFF_MASK, cf->can_dlc);
-       else
-               sprintf(sl->xbuff, "%c%03X%d", cmd | 0x20,
-                       cf->can_id & CAN_SFF_MASK, cf->can_dlc);
+       /* determine number of chars for the CAN-identifier */
+       if (cf->can_id & CAN_EFF_FLAG) {
+               id &= CAN_EFF_MASK;
+               endpos = pos + SLC_EFF_ID_LEN;
+       } else {
+               *pos |= 0x20; /* convert R/T to lower case for SFF */
+               id &= CAN_SFF_MASK;
+               endpos = pos + SLC_SFF_ID_LEN;
+       }
 
-       idx = strlen(sl->xbuff);
+       /* build 3 (SFF) or 8 (EFF) digit CAN identifier */
+       pos++;
+       while (endpos >= pos) {
+               *endpos-- = hex_asc_upper[id & 0xf];
+               id >>= 4;
+       }
+
+       pos += (cf->can_id & CAN_EFF_FLAG) ? SLC_EFF_ID_LEN : SLC_SFF_ID_LEN;
 
-       for (i = 0; i < cf->can_dlc; i++)
-               sprintf(&sl->xbuff[idx + 2*i], "%02X", cf->data[i]);
+       *pos++ = cf->can_dlc + '0';
+
+       /* RTR frames may have a dlc > 0 but they never have any data bytes */
+       if (!(cf->can_id & CAN_RTR_FLAG)) {
+               for (i = 0; i < cf->can_dlc; i++)
+                       pos = hex_byte_pack_upper(pos, cf->data[i]);
+       }
 
-       strcat(sl->xbuff, "\r"); /* add terminating character */
+       *pos++ = '\r';
 
        /* Order of next two lines is *very* important.
         * When we are sending a little amount of data,
@@ -267,8 +305,8 @@ static void slc_encaps(struct slcan *sl, struct can_frame *cf)
         *       14 Oct 1994  Dmitry Gorodchanin.
         */
        set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
-       actual = sl->tty->ops->write(sl->tty, sl->xbuff, strlen(sl->xbuff));
-       sl->xleft = strlen(sl->xbuff) - actual;
+       actual = sl->tty->ops->write(sl->tty, sl->xbuff, pos - sl->xbuff);
+       sl->xleft = (pos - sl->xbuff) - actual;
        sl->xhead = sl->xbuff + actual;
        sl->dev->stats.tx_bytes += cf->can_dlc;
 }
@@ -286,11 +324,13 @@ static void slcan_write_wakeup(struct tty_struct *tty)
        if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
                return;
 
+       spin_lock(&sl->lock);
        if (sl->xleft <= 0)  {
                /* Now serial buffer is almost free & we can start
                 * transmission of another packet */
                sl->dev->stats.tx_packets++;
                clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+               spin_unlock(&sl->lock);
                netif_wake_queue(sl->dev);
                return;
        }
@@ -298,6 +338,7 @@ static void slcan_write_wakeup(struct tty_struct *tty)
        actual = tty->ops->write(tty, sl->xhead, sl->xleft);
        sl->xleft -= actual;
        sl->xhead += actual;
+       spin_unlock(&sl->lock);
 }
 
 /* Send a can_frame to a TTY queue. */
index a0f647f92bf55c7388034f9fbd0a377cc1225901..0b7a4c3b01a2976176878607bd457a9ea282e21e 100644 (file)
@@ -463,7 +463,7 @@ static int peak_usb_start(struct peak_usb_device *dev)
        if (i < PCAN_USB_MAX_TX_URBS) {
                if (i == 0) {
                        netdev_err(netdev, "couldn't setup any tx URB\n");
-                       return err;
+                       goto err_tx;
                }
 
                netdev_warn(netdev, "tx performance may be slow\n");
@@ -472,7 +472,7 @@ static int peak_usb_start(struct peak_usb_device *dev)
        if (dev->adapter->dev_start) {
                err = dev->adapter->dev_start(dev);
                if (err)
-                       goto failed;
+                       goto err_adapter;
        }
 
        dev->state |= PCAN_USB_STATE_STARTED;
@@ -481,19 +481,26 @@ static int peak_usb_start(struct peak_usb_device *dev)
        if (dev->adapter->dev_set_bus) {
                err = dev->adapter->dev_set_bus(dev, 1);
                if (err)
-                       goto failed;
+                       goto err_adapter;
        }
 
        dev->can.state = CAN_STATE_ERROR_ACTIVE;
 
        return 0;
 
-failed:
+err_adapter:
        if (err == -ENODEV)
                netif_device_detach(dev->netdev);
 
        netdev_warn(netdev, "couldn't submit control: %d\n", err);
 
+       for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) {
+               usb_free_urb(dev->tx_contexts[i].urb);
+               dev->tx_contexts[i].urb = NULL;
+       }
+err_tx:
+       usb_kill_anchored_urbs(&dev->rx_submitted);
+
        return err;
 }
 
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..e66beff2704d19241695fe5028e33efb3ca95519 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",
@@ -2473,8 +2481,7 @@ load_error_cnic2:
 load_error_cnic1:
        bnx2x_napi_disable_cnic(bp);
        /* Update the number of queues without the cnic queues */
-       rc = bnx2x_set_real_num_queues(bp, 0);
-       if (rc)
+       if (bnx2x_set_real_num_queues(bp, 0))
                BNX2X_ERR("Unable to set real_num_queues not including cnic\n");
 load_error_cnic0:
        BNX2X_ERR("CNIC-related load failed\n");
@@ -3000,16 +3007,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 +3040,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 +4228,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 664568420c9bdd08869e33802ee8c208e307c082..51468227bf3b75fc17d2abafb8b3bd9294d8494c 100644 (file)
@@ -175,6 +175,7 @@ typedef int (*read_sfp_module_eeprom_func_p)(struct bnx2x_phy *phy,
 #define EDC_MODE_LINEAR                                0x0022
 #define EDC_MODE_LIMITING                              0x0044
 #define EDC_MODE_PASSIVE_DAC                   0x0055
+#define EDC_MODE_ACTIVE_DAC                    0x0066
 
 /* ETS defines*/
 #define DCBX_INVALID_COS                                       (0xFF)
@@ -3684,6 +3685,41 @@ static void bnx2x_warpcore_enable_AN_KR2(struct bnx2x_phy *phy,
        bnx2x_update_link_attr(params, vars->link_attr_sync);
 }
 
+static void bnx2x_disable_kr2(struct link_params *params,
+                             struct link_vars *vars,
+                             struct bnx2x_phy *phy)
+{
+       struct bnx2x *bp = params->bp;
+       int i;
+       static struct bnx2x_reg_set reg_set[] = {
+               /* Step 1 - Program the TX/RX alignment markers */
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL5, 0x7690},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL7, 0xe647},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL6, 0xc4f0},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL9, 0x7690},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_RX_CTRL11, 0xe647},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_RX_CTRL10, 0xc4f0},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_USERB0_CTRL, 0x000c},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CTRL1, 0x6000},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CTRL3, 0x0000},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CODE_FIELD, 0x0002},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI1, 0x0000},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI2, 0x0af7},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI3, 0x0af7},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_LD_BAM_CODE, 0x0002},
+               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_LD_UD_CODE, 0x0000}
+       };
+       DP(NETIF_MSG_LINK, "Disabling 20G-KR2\n");
+
+       for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+               bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
+                                reg_set[i].val);
+       vars->link_attr_sync &= ~LINK_ATTR_SYNC_KR2_ENABLE;
+       bnx2x_update_link_attr(params, vars->link_attr_sync);
+
+       vars->check_kr2_recovery_cnt = CHECK_KR2_RECOVERY_CNT;
+}
+
 static void bnx2x_warpcore_set_lpi_passthrough(struct bnx2x_phy *phy,
                                               struct link_params *params)
 {
@@ -3715,7 +3751,6 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
                                        struct link_params *params,
                                        struct link_vars *vars) {
        u16 lane, i, cl72_ctrl, an_adv = 0;
-       u16 ucode_ver;
        struct bnx2x *bp = params->bp;
        static struct bnx2x_reg_set reg_set[] = {
                {MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7},
@@ -3806,15 +3841,7 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
 
        /* Advertise pause */
        bnx2x_ext_phy_set_pause(params, phy, vars);
-       /* Set KR Autoneg Work-Around flag for Warpcore version older than D108
-        */
-       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-                       MDIO_WC_REG_UC_INFO_B1_VERSION, &ucode_ver);
-       if (ucode_ver < 0xd108) {
-               DP(NETIF_MSG_LINK, "Enable AN KR work-around. WC ver:0x%x\n",
-                              ucode_ver);
-               vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
-       }
+       vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
        bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
                                 MDIO_WC_REG_DIGITAL5_MISC7, 0x100);
 
@@ -3838,6 +3865,8 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
                bnx2x_set_aer_mmd(params, phy);
 
                bnx2x_warpcore_enable_AN_KR2(phy, params, vars);
+       } else {
+               bnx2x_disable_kr2(params, vars, phy);
        }
 
        /* Enable Autoneg: only on the main lane */
@@ -4347,20 +4376,14 @@ static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
        struct bnx2x *bp = params->bp;
        u32 serdes_net_if;
        u16 gp_status1 = 0, lnkup = 0, lnkup_kr = 0;
-       u16 lane = bnx2x_get_warpcore_lane(phy, params);
 
        vars->turn_to_run_wc_rt = vars->turn_to_run_wc_rt ? 0 : 1;
 
        if (!vars->turn_to_run_wc_rt)
                return;
 
-       /* Return if there is no link partner */
-       if (!(bnx2x_warpcore_get_sigdet(phy, params))) {
-               DP(NETIF_MSG_LINK, "bnx2x_warpcore_get_sigdet false\n");
-               return;
-       }
-
        if (vars->rx_tx_asic_rst) {
+               u16 lane = bnx2x_get_warpcore_lane(phy, params);
                serdes_net_if = (REG_RD(bp, params->shmem_base +
                                offsetof(struct shmem_region, dev_info.
                                port_hw_config[params->port].default_cfg)) &
@@ -4375,14 +4398,8 @@ static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
                                /*10G KR*/
                        lnkup_kr = (gp_status1 >> (12+lane)) & 0x1;
 
-                       DP(NETIF_MSG_LINK,
-                               "gp_status1 0x%x\n", gp_status1);
-
                        if (lnkup_kr || lnkup) {
-                                       vars->rx_tx_asic_rst = 0;
-                                       DP(NETIF_MSG_LINK,
-                                       "link up, rx_tx_asic_rst 0x%x\n",
-                                       vars->rx_tx_asic_rst);
+                               vars->rx_tx_asic_rst = 0;
                        } else {
                                /* Reset the lane to see if link comes up.*/
                                bnx2x_warpcore_reset_lane(bp, phy, 1);
@@ -4507,10 +4524,14 @@ static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
                         * enabled transmitter to avoid current leakage in case
                         * no module is connected
                         */
-                       if (bnx2x_is_sfp_module_plugged(phy, params))
-                               bnx2x_sfp_module_detection(phy, params);
-                       else
-                               bnx2x_sfp_e3_set_transmitter(params, phy, 1);
+                       if ((params->loopback_mode == LOOPBACK_NONE) ||
+                           (params->loopback_mode == LOOPBACK_EXT)) {
+                               if (bnx2x_is_sfp_module_plugged(phy, params))
+                                       bnx2x_sfp_module_detection(phy, params);
+                               else
+                                       bnx2x_sfp_e3_set_transmitter(params,
+                                                                    phy, 1);
+                       }
 
                        bnx2x_warpcore_config_sfi(phy, params);
                        break;
@@ -5757,6 +5778,11 @@ static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy,
        rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, gp_speed,
                                         duplex);
 
+       /* In case of KR link down, start up the recovering procedure */
+       if ((!link_up) && (phy->media_type == ETH_PHY_KR) &&
+           (!(phy->flags & FLAGS_WC_DUAL_MODE)))
+               vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
+
        DP(NETIF_MSG_LINK, "duplex %x  flow_ctrl 0x%x link_status 0x%x\n",
                   vars->duplex, vars->flow_ctrl, vars->link_status);
        return rc;
@@ -6501,15 +6527,17 @@ static int bnx2x_link_initialize(struct link_params *params,
                struct bnx2x_phy *phy = &params->phy[INT_PHY];
                if (vars->line_speed == SPEED_AUTO_NEG &&
                    (CHIP_IS_E1x(bp) ||
-                    CHIP_IS_E2(bp))) {
+                    CHIP_IS_E2(bp)))
                        bnx2x_set_parallel_detection(phy, params);
-                       if (params->phy[INT_PHY].config_init)
-                               params->phy[INT_PHY].config_init(phy,
-                                                                params,
-                                                                vars);
-               }
+               if (params->phy[INT_PHY].config_init)
+                       params->phy[INT_PHY].config_init(phy, params, vars);
        }
 
+       /* Re-read this value in case it was changed inside config_init due to
+        * limitations of optic module
+        */
+       vars->line_speed = params->phy[INT_PHY].req_line_speed;
+
        /* Init external phy*/
        if (non_ext_phy) {
                if (params->phy[INT_PHY].supported &
@@ -8083,7 +8111,10 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
                if (copper_module_type &
                    SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
                        DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
-                       check_limiting_mode = 1;
+                       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
+                               *edc_mode = EDC_MODE_ACTIVE_DAC;
+                       else
+                               check_limiting_mode = 1;
                } else if (copper_module_type &
                        SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
                                DP(NETIF_MSG_LINK,
@@ -8558,6 +8589,7 @@ static void bnx2x_warpcore_set_limiting_mode(struct link_params *params,
                mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT;
                break;
        case EDC_MODE_PASSIVE_DAC:
+       case EDC_MODE_ACTIVE_DAC:
                mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_SFP_DAC;
                break;
        default:
@@ -9733,32 +9765,41 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
                         MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
                         an_1000_val);
 
-       /* set 100 speed advertisement */
-       if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
-            (phy->speed_cap_mask &
-             (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
-              PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF))) {
-               an_10_100_val |= (1<<7);
-               /* Enable autoneg and restart autoneg for legacy speeds */
-               autoneg_val |= (1<<9 | 1<<12);
-
-               if (phy->req_duplex == DUPLEX_FULL)
+       /* Set 10/100 speed advertisement */
+       if (phy->req_line_speed == SPEED_AUTO_NEG) {
+               if (phy->speed_cap_mask &
+                   PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL) {
+                       /* Enable autoneg and restart autoneg for legacy speeds
+                        */
+                       autoneg_val |= (1<<9 | 1<<12);
                        an_10_100_val |= (1<<8);
-               DP(NETIF_MSG_LINK, "Advertising 100M\n");
-       }
-       /* set 10 speed advertisement */
-       if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
-            (phy->speed_cap_mask &
-             (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
-              PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) &&
-            (phy->supported &
-             (SUPPORTED_10baseT_Half |
-              SUPPORTED_10baseT_Full)))) {
-               an_10_100_val |= (1<<5);
-               autoneg_val |= (1<<9 | 1<<12);
-               if (phy->req_duplex == DUPLEX_FULL)
+                       DP(NETIF_MSG_LINK, "Advertising 100M-FD\n");
+               }
+
+               if (phy->speed_cap_mask &
+                   PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF) {
+                       /* Enable autoneg and restart autoneg for legacy speeds
+                        */
+                       autoneg_val |= (1<<9 | 1<<12);
+                       an_10_100_val |= (1<<7);
+                       DP(NETIF_MSG_LINK, "Advertising 100M-HD\n");
+               }
+
+               if ((phy->speed_cap_mask &
+                    PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
+                   (phy->supported & SUPPORTED_10baseT_Full)) {
                        an_10_100_val |= (1<<6);
-               DP(NETIF_MSG_LINK, "Advertising 10M\n");
+                       autoneg_val |= (1<<9 | 1<<12);
+                       DP(NETIF_MSG_LINK, "Advertising 10M-FD\n");
+               }
+
+               if ((phy->speed_cap_mask &
+                    PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF) &&
+                   (phy->supported & SUPPORTED_10baseT_Half)) {
+                       an_10_100_val |= (1<<5);
+                       autoneg_val |= (1<<9 | 1<<12);
+                       DP(NETIF_MSG_LINK, "Advertising 10M-HD\n");
+               }
        }
 
        /* Only 10/100 are allowed to work in FORCE mode */
@@ -13435,43 +13476,6 @@ static void bnx2x_sfp_tx_fault_detection(struct bnx2x_phy *phy,
                }
        }
 }
-static void bnx2x_disable_kr2(struct link_params *params,
-                             struct link_vars *vars,
-                             struct bnx2x_phy *phy)
-{
-       struct bnx2x *bp = params->bp;
-       int i;
-       static struct bnx2x_reg_set reg_set[] = {
-               /* Step 1 - Program the TX/RX alignment markers */
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL5, 0x7690},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL7, 0xe647},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL6, 0xc4f0},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL9, 0x7690},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_RX_CTRL11, 0xe647},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_RX_CTRL10, 0xc4f0},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_USERB0_CTRL, 0x000c},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CTRL1, 0x6000},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CTRL3, 0x0000},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CODE_FIELD, 0x0002},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI1, 0x0000},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI2, 0x0af7},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI3, 0x0af7},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_LD_BAM_CODE, 0x0002},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_LD_UD_CODE, 0x0000}
-       };
-       DP(NETIF_MSG_LINK, "Disabling 20G-KR2\n");
-
-       for (i = 0; i < ARRAY_SIZE(reg_set); i++)
-               bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
-                                reg_set[i].val);
-       vars->link_attr_sync &= ~LINK_ATTR_SYNC_KR2_ENABLE;
-       bnx2x_update_link_attr(params, vars->link_attr_sync);
-
-       vars->check_kr2_recovery_cnt = CHECK_KR2_RECOVERY_CNT;
-       /* Restart AN on leading lane */
-       bnx2x_warpcore_restart_AN_KR(phy, params);
-}
-
 static void bnx2x_kr2_recovery(struct link_params *params,
                               struct link_vars *vars,
                               struct bnx2x_phy *phy)
@@ -13549,6 +13553,8 @@ static void bnx2x_check_kr2_wa(struct link_params *params,
                /* Disable KR2 on both lanes */
                DP(NETIF_MSG_LINK, "BP=0x%x, NP=0x%x\n", base_page, next_page);
                bnx2x_disable_kr2(params, vars, phy);
+               /* Restart AN on leading lane */
+               bnx2x_warpcore_restart_AN_KR(phy, params);
                return;
        }
 }
index 634a793c1c462ab429261a7388867db81bfaaeb8..82b658d8c04c47c52931b5138375cd38f0ca519a 100644 (file)
@@ -4703,6 +4703,14 @@ bool bnx2x_chk_parity_attn(struct bnx2x *bp, bool *global, bool print)
        attn.sig[3] = REG_RD(bp,
                MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 +
                             port*4);
+       /* Since MCP attentions can't be disabled inside the block, we need to
+        * read AEU registers to see whether they're currently disabled
+        */
+       attn.sig[3] &= ((REG_RD(bp,
+                               !port ? MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0
+                                     : MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0) &
+                        MISC_AEU_ENABLE_MCP_PRTY_BITS) |
+                       ~MISC_AEU_ENABLE_MCP_PRTY_BITS);
 
        if (!CHIP_IS_E1x(bp))
                attn.sig[4] = REG_RD(bp,
@@ -5447,26 +5455,24 @@ static void bnx2x_timer(unsigned long data)
        if (IS_PF(bp) &&
            !BP_NOMCP(bp)) {
                int mb_idx = BP_FW_MB_IDX(bp);
-               u32 drv_pulse;
-               u32 mcp_pulse;
+               u16 drv_pulse;
+               u16 mcp_pulse;
 
                ++bp->fw_drv_pulse_wr_seq;
                bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK;
-               /* TBD - add SYSTEM_TIME */
                drv_pulse = bp->fw_drv_pulse_wr_seq;
                bnx2x_drv_pulse(bp);
 
                mcp_pulse = (SHMEM_RD(bp, func_mb[mb_idx].mcp_pulse_mb) &
                             MCP_PULSE_SEQ_MASK);
                /* The delta between driver pulse and mcp response
-                * should be 1 (before mcp response) or 0 (after mcp response)
+                * should not get too big. If the MFW is more than 5 pulses
+                * behind, we should worry about it enough to generate an error
+                * log.
                 */
-               if ((drv_pulse != mcp_pulse) &&
-                   (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) {
-                       /* someone lost a heartbeat... */
-                       BNX2X_ERR("drv_pulse (0x%x) != mcp_pulse (0x%x)\n",
+               if (((drv_pulse - mcp_pulse) & MCP_PULSE_SEQ_MASK) > 5)
+                       BNX2X_ERR("MFW seems hanged: drv_pulse (0x%x) != mcp_pulse (0x%x)\n",
                                  drv_pulse, mcp_pulse);
-               }
        }
 
        if (bp->state == BNX2X_STATE_OPEN)
@@ -7645,6 +7651,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 +8658,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 +8675,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 +10406,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 +12148,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 +13638,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..9ad012bdd9151e44ce699b640e77273ad9901796 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);
 }
@@ -1822,7 +1819,7 @@ bnx2x_get_vf_igu_cam_info(struct bnx2x *bp)
                fid = GET_FIELD((val), IGU_REG_MAPPING_MEMORY_FID);
                if (fid & IGU_FID_ENCODE_IS_PF)
                        current_pf = fid & IGU_FID_PF_NUM_MASK;
-               else if (current_pf == BP_ABS_FUNC(bp))
+               else if (current_pf == BP_FUNC(bp))
                        bnx2x_vf_set_igu_info(bp, sb_id,
                                              (fid & IGU_FID_VF_NUM_MASK));
                DP(BNX2X_MSG_IOV, "%s[%d], igu_sb_id=%d, msix=%d\n",
@@ -3183,6 +3180,7 @@ int bnx2x_enable_sriov(struct bnx2x *bp)
                /* set local queue arrays */
                vf->vfqs = &bp->vfdb->vfqs[qcount];
                qcount += vf_sb_count(vf);
+               bnx2x_iov_static_resc(bp, vf);
        }
 
        /* prepare msix vectors in VF configuration space */
@@ -3190,6 +3188,8 @@ int bnx2x_enable_sriov(struct bnx2x *bp)
                bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf_idx));
                REG_WR(bp, PCICFG_OFFSET + GRC_CONFIG_REG_VF_MSIX_CONTROL,
                       num_vf_queues);
+               DP(BNX2X_MSG_IOV, "set msix vec num in VF %d cfg space to %d\n",
+                  vf_idx, num_vf_queues);
        }
        bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
 
index 2a8c1dc65d9cd6c3a0168bf1c5d12ee0b6b58bcc..059f0d460af2a249e631a913ec98da290d78f323 100644 (file)
@@ -816,6 +816,8 @@ static inline int bnx2x_vfpf_setup_q(struct bnx2x *bp, struct bnx2x_fastpath *fp
 static inline int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) {return 0; }
 static inline int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr,
                                        u8 vf_qid, bool set) {return 0; }
+static inline int bnx2x_vfpf_config_rss(struct bnx2x *bp,
+                                       struct bnx2x_config_rss_params *params) {return 0; }
 static inline int bnx2x_vfpf_set_mcast(struct net_device *dev) {return 0; }
 static inline int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp) {return 0; }
 static inline int bnx2x_iov_nic_init(struct bnx2x *bp) {return 0; }
index 6cfb8873245281a74222926b6052838d6df1eca0..da16953eb2ec58012f059273abf153c7e81293b9 100644 (file)
@@ -1765,28 +1765,28 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
                switch (mbx->first_tlv.tl.type) {
                case CHANNEL_TLV_ACQUIRE:
                        bnx2x_vf_mbx_acquire(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_INIT:
                        bnx2x_vf_mbx_init_vf(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_SETUP_Q:
                        bnx2x_vf_mbx_setup_q(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_SET_Q_FILTERS:
                        bnx2x_vf_mbx_set_q_filters(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_TEARDOWN_Q:
                        bnx2x_vf_mbx_teardown_q(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_CLOSE:
                        bnx2x_vf_mbx_close_vf(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_RELEASE:
                        bnx2x_vf_mbx_release_vf(bp, vf, mbx);
-                       break;
+                       return;
                case CHANNEL_TLV_UPDATE_RSS:
                        bnx2x_vf_mbx_update_rss(bp, vf, mbx);
-                       break;
+                       return;
                }
 
        } else {
@@ -1802,26 +1802,24 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
                for (i = 0; i < 20; i++)
                        DP_CONT(BNX2X_MSG_IOV, "%x ",
                                mbx->msg->req.tlv_buf_size.tlv_buffer[i]);
+       }
 
-               /* test whether we can respond to the VF (do we have an address
-                * for it?)
-                */
-               if (vf->state == VF_ACQUIRED || vf->state == VF_ENABLED) {
-                       /* mbx_resp uses the op_rc of the VF */
-                       vf->op_rc = PFVF_STATUS_NOT_SUPPORTED;
+       /* can we respond to VF (do we have an address for it?) */
+       if (vf->state == VF_ACQUIRED || vf->state == VF_ENABLED) {
+               /* mbx_resp uses the op_rc of the VF */
+               vf->op_rc = PFVF_STATUS_NOT_SUPPORTED;
 
-                       /* notify the VF that we do not support this request */
-                       bnx2x_vf_mbx_resp(bp, vf);
-               } else {
-                       /* can't send a response since this VF is unknown to us
-                        * just ack the FW to release the mailbox and unlock
-                        * the channel.
-                        */
-                       storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
-                       mmiowb();
-                       bnx2x_unlock_vf_pf_channel(bp, vf,
-                                                  mbx->first_tlv.tl.type);
-               }
+               /* notify the VF that we do not support this request */
+               bnx2x_vf_mbx_resp(bp, vf);
+       } else {
+               /* can't send a response since this VF is unknown to us
+                * just ack the FW to release the mailbox and unlock
+                * the channel.
+                */
+               storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
+               /* Firmware ack should be written before unlocking channel */
+               mmiowb();
+               bnx2x_unlock_vf_pf_channel(bp, vf, mbx->first_tlv.tl.type);
        }
 }
 
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 ace5050dba3877ca8a3fe4995469ee3d16837c55..db020230bd0bba5ec72186bed9539357ec315abc 100644 (file)
@@ -88,6 +88,7 @@ static inline char *nic_name(struct pci_dev *pdev)
 #define BE_MIN_MTU             256
 
 #define BE_NUM_VLANS_SUPPORTED 64
+#define BE_UMC_NUM_VLANS_SUPPORTED     15
 #define BE_MAX_EQD             96u
 #define        BE_MAX_TX_FRAG_COUNT    30
 
@@ -333,6 +334,7 @@ enum vf_state {
 
 #define BE_FLAGS_LINK_STATUS_INIT              1
 #define BE_FLAGS_WORKER_SCHEDULED              (1 << 3)
+#define BE_FLAGS_VLAN_PROMISC                  (1 << 4)
 #define BE_FLAGS_NAPI_ENABLED                  (1 << 9)
 #define BE_UC_PMAC_COUNT               30
 #define BE_VF_UC_PMAC_COUNT            2
index 1ab5dab11eff07ab349a0cc795ef5986fe1e9010..bd0e0c0bbcd8e0e21d5295ef92aea6fb769d2c69 100644 (file)
@@ -180,6 +180,9 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
                        dev_err(&adapter->pdev->dev,
                                "opcode %d-%d failed:status %d-%d\n",
                                opcode, subsystem, compl_status, extd_status);
+
+                       if (extd_status == MCC_ADDL_STS_INSUFFICIENT_RESOURCES)
+                               return extd_status;
                }
        }
 done:
@@ -1812,6 +1815,12 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
        } else if (flags & IFF_ALLMULTI) {
                req->if_flags_mask = req->if_flags =
                                cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS);
+       } else if (flags & BE_FLAGS_VLAN_PROMISC) {
+               req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS);
+
+               if (value == ON)
+                       req->if_flags =
+                               cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS);
        } else {
                struct netdev_hw_addr *ha;
                int i = 0;
index d026226db88ccac0fcc70497ce2c8f6ef7b3e614..108ca8abf0af2321a6f5db5fe289af658b0bfcdf 100644 (file)
@@ -60,6 +60,8 @@ enum {
        MCC_STATUS_NOT_SUPPORTED = 66
 };
 
+#define MCC_ADDL_STS_INSUFFICIENT_RESOURCES    0x16
+
 #define CQE_STATUS_COMPL_MASK          0xFFFF
 #define CQE_STATUS_COMPL_SHIFT         0       /* bits 0 - 15 */
 #define CQE_STATUS_EXTD_MASK           0xFFFF
@@ -1791,7 +1793,7 @@ struct be_nic_res_desc {
        u8 acpi_params;
        u8 wol_param;
        u16 rsvd7;
-       u32 rsvd8[3];
+       u32 rsvd8[7];
 } __packed;
 
 struct be_cmd_req_get_func_config {
index 3224d28cdad4384d4322bd5765d503ef9ace1ca1..2c38cc402119c763021ea77461455fd0fa8ac035 100644 (file)
@@ -855,11 +855,11 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
        unsigned int eth_hdr_len;
        struct iphdr *ip;
 
-       /* Lancer ASIC has a bug wherein packets that are 32 bytes or less
+       /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or less
         * may cause a transmit stall on that port. So the work-around is to
-        * pad such packets to a 36-byte length.
+        * pad short packets (<= 32 bytes) to a 36-byte length.
         */
-       if (unlikely(lancer_chip(adapter) && skb->len <= 32)) {
+       if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
                if (skb_padto(skb, 36))
                        goto tx_drop;
                skb->len = 36;
@@ -1013,18 +1013,40 @@ static int be_vid_config(struct be_adapter *adapter)
        status = be_cmd_vlan_config(adapter, adapter->if_handle,
                                    vids, num, 1, 0);
 
-       /* Set to VLAN promisc mode as setting VLAN filter failed */
        if (status) {
-               dev_info(&adapter->pdev->dev, "Exhausted VLAN HW filters.\n");
-               dev_info(&adapter->pdev->dev, "Disabling HW VLAN filtering.\n");
-               goto set_vlan_promisc;
+               /* Set to VLAN promisc mode as setting VLAN filter failed */
+               if (status == MCC_ADDL_STS_INSUFFICIENT_RESOURCES)
+                       goto set_vlan_promisc;
+               dev_err(&adapter->pdev->dev,
+                       "Setting HW VLAN filtering failed.\n");
+       } else {
+               if (adapter->flags & BE_FLAGS_VLAN_PROMISC) {
+                       /* hw VLAN filtering re-enabled. */
+                       status = be_cmd_rx_filter(adapter,
+                                                 BE_FLAGS_VLAN_PROMISC, OFF);
+                       if (!status) {
+                               dev_info(&adapter->pdev->dev,
+                                        "Disabling VLAN Promiscuous mode.\n");
+                               adapter->flags &= ~BE_FLAGS_VLAN_PROMISC;
+                               dev_info(&adapter->pdev->dev,
+                                        "Re-Enabling HW VLAN filtering\n");
+                       }
+               }
        }
 
        return status;
 
 set_vlan_promisc:
-       status = be_cmd_vlan_config(adapter, adapter->if_handle,
-                                   NULL, 0, 1, 1);
+       dev_warn(&adapter->pdev->dev, "Exhausted VLAN HW filters.\n");
+
+       status = be_cmd_rx_filter(adapter, BE_FLAGS_VLAN_PROMISC, ON);
+       if (!status) {
+               dev_info(&adapter->pdev->dev, "Enable VLAN Promiscuous mode\n");
+               dev_info(&adapter->pdev->dev, "Disabling HW VLAN filtering\n");
+               adapter->flags |= BE_FLAGS_VLAN_PROMISC;
+       } else
+               dev_err(&adapter->pdev->dev,
+                       "Failed to enable VLAN Promiscuous mode.\n");
        return status;
 }
 
@@ -1033,10 +1055,6 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
        struct be_adapter *adapter = netdev_priv(netdev);
        int status = 0;
 
-       if (!lancer_chip(adapter) && !be_physfn(adapter)) {
-               status = -EINVAL;
-               goto ret;
-       }
 
        /* Packets with VID 0 are always received by Lancer by default */
        if (lancer_chip(adapter) && vid == 0)
@@ -1059,11 +1077,6 @@ static int be_vlan_rem_vid(struct net_device *netdev, __be16 proto, u16 vid)
        struct be_adapter *adapter = netdev_priv(netdev);
        int status = 0;
 
-       if (!lancer_chip(adapter) && !be_physfn(adapter)) {
-               status = -EINVAL;
-               goto ret;
-       }
-
        /* Packets with VID 0 are always received by Lancer by default */
        if (lancer_chip(adapter) && vid == 0)
                goto ret;
@@ -1188,8 +1201,8 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
 
        vi->vf = vf;
        vi->tx_rate = vf_cfg->tx_rate;
-       vi->vlan = vf_cfg->vlan_tag;
-       vi->qos = 0;
+       vi->vlan = vf_cfg->vlan_tag & VLAN_VID_MASK;
+       vi->qos = vf_cfg->vlan_tag >> VLAN_PRIO_SHIFT;
        memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN);
 
        return 0;
@@ -1199,28 +1212,29 @@ static int be_set_vf_vlan(struct net_device *netdev,
                        int vf, u16 vlan, u8 qos)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
        int status = 0;
 
        if (!sriov_enabled(adapter))
                return -EPERM;
 
-       if (vf >= adapter->num_vfs || vlan > 4095)
+       if (vf >= adapter->num_vfs || vlan > 4095 || qos > 7)
                return -EINVAL;
 
-       if (vlan) {
-               if (adapter->vf_cfg[vf].vlan_tag != vlan) {
+       if (vlan || qos) {
+               vlan |= qos << VLAN_PRIO_SHIFT;
+               if (vf_cfg->vlan_tag != vlan) {
                        /* If this is new value, program it. Else skip. */
-                       adapter->vf_cfg[vf].vlan_tag = vlan;
-
-                       status = be_cmd_set_hsw_config(adapter, vlan,
-                               vf + 1, adapter->vf_cfg[vf].if_handle, 0);
+                       vf_cfg->vlan_tag = vlan;
+                       status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
+                                                      vf_cfg->if_handle, 0);
                }
        } else {
                /* Reset Transparent Vlan Tagging. */
-               adapter->vf_cfg[vf].vlan_tag = 0;
-               vlan = adapter->vf_cfg[vf].def_vid;
+               vf_cfg->vlan_tag = 0;
+               vlan = vf_cfg->def_vid;
                status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
-                       adapter->vf_cfg[vf].if_handle, 0);
+                                              vf_cfg->if_handle, 0);
        }
 
 
@@ -2802,7 +2816,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;
@@ -2963,6 +2977,8 @@ static void BEx_get_resources(struct be_adapter *adapter,
 
        if (adapter->function_mode & FLEX10_MODE)
                res->max_vlans = BE_NUM_VLANS_SUPPORTED/8;
+       else if (adapter->function_mode & UMC_ENABLED)
+               res->max_vlans = BE_UMC_NUM_VLANS_SUPPORTED;
        else
                res->max_vlans = BE_NUM_VLANS_SUPPORTED;
        res->max_mcast_mac = BE_MAX_MC;
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 098f133908ae016058f326225e2ed58b9709d592..e006a09ba8990050f3bc9a91e101ae8455419a87 100644 (file)
@@ -452,7 +452,9 @@ static int gianfar_ptp_probe(struct platform_device *dev)
        err = -ENODEV;
 
        etsects->caps = ptp_gianfar_caps;
-       etsects->cksel = DEFAULT_CKSEL;
+
+       if (get_of_u32(node, "fsl,cksel", &etsects->cksel))
+               etsects->cksel = DEFAULT_CKSEL;
 
        if (get_of_u32(node, "fsl,tclk-period", &etsects->tclk_period) ||
            get_of_u32(node, "fsl,tmr-prsc", &etsects->tmr_prsc) ||
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..cfef7fc
--- /dev/null
@@ -0,0 +1,982 @@
+/*******************************************************************************
+ *
+ * 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) {
+               *details = *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 */
+       *desc_on_ring = *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)) {
+               *desc = *desc_on_ring;
+               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..1e4ea13
--- /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)
+               *link = *hw_link_info;
+
+       /* 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..221aa47
--- /dev/null
@@ -0,0 +1,7377 @@
+/*******************************************************************************
+ *
+ * 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 -ENOMEM;
+
+       return 0;
+}
+
+/**
+ * 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 -ENOMEM;
+
+       return 0;
+}
+
+/**
+ * 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, j;
+
+       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) {
+               /* 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;
+                       break;
+               } 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 aq_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) {
+                               aq_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 (aq_ret)
+                                       dev_info(&pf->pdev->dev,
+                                                "ignoring delete macvlan error, err %d, aq_err %d while flushing a full buffer\n",
+                                                aq_ret,
+                                                pf->hw.aq.asq_last_status);
+                       }
+               }
+               if (num_del) {
+                       aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid,
+                                                    del_list, num_del, NULL);
+                       num_del = 0;
+
+                       if (aq_ret)
+                               dev_info(&pf->pdev->dev,
+                                        "ignoring delete macvlan error, err %d, aq_err %d\n",
+                                        aq_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) {
+                               aq_ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid,
+                                                            add_list, num_add,
+                                                            NULL);
+                               num_add = 0;
+
+                               if (aq_ret)
+                                       break;
+                               memset(add_list, 0, sizeof(*add_list));
+                       }
+               }
+               if (num_add) {
+                       aq_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 && (!aq_ret)) {
+                       /* do nothing */;
+               } else if (add_happened && (aq_ret)) {
+                       dev_info(&pf->pdev->dev,
+                                "add filter failed, err %d, aq_err %d\n",
+                                aq_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);
+               aq_ret = i40e_aq_set_vsi_multicast_promiscuous(&vsi->back->hw,
+                                                              vsi->seid,
+                                                              cur_multipromisc,
+                                                              NULL);
+               if (aq_ret)
+                       dev_info(&pf->pdev->dev,
+                                "set multi promisc failed, err %d, aq_err %d\n",
+                                aq_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));
+               aq_ret = i40e_aq_set_vsi_unicast_promiscuous(&vsi->back->hw,
+                                                            vsi->seid,
+                                                            cur_promisc, NULL);
+               if (aq_ret)
+                       dev_info(&pf->pdev->dev,
+                                "set uni promisc failed, err %d, aq_err %d\n",
+                                aq_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)
+ *
+ * Return: 0 on success or negative otherwise
+ **/
+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
+ *
+ * net_device_ops implementation for adding vlan ids
+ **/
+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 = 0;
+
+       if (vid > 4095)
+               return -EINVAL;
+
+       netdev_info(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 && (vid < VLAN_N_VID))
+               set_bit(vid, vsi->active_vlans);
+
+       return ret;
+}
+
+/**
+ * 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
+ *
+ * net_device_ops implementation for adding vlan ids
+ **/
+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(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 the other 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
+ **/
+int i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid)
+{
+       struct i40e_vsi_context ctxt;
+       i40e_status aq_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));
+       aq_ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL);
+       if (aq_ret) {
+               dev_info(&vsi->back->pdev->dev,
+                        "%s: update vsi failed, aq_err=%d\n",
+                        __func__, vsi->back->hw.aq.asq_last_status);
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
+/**
+ * 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)
+{
+       u8 num_tc = 0;
+       int 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
+        */
+       return num_tc + 1;
+}
+
+/**
+ * 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;
+       i40e_status aq_ret;
+       u32 tc_bw_max;
+       int i;
+
+       /* Get the VSI level BW configuration */
+       aq_ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL);
+       if (aq_ret) {
+               dev_info(&pf->pdev->dev,
+                        "couldn't get pf vsi bw config, err %d, aq_err %d\n",
+                        aq_ret, pf->hw.aq.asq_last_status);
+               return -EINVAL;
+       }
+
+       /* Get the VSI level BW configuration per TC */
+       aq_ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid, &bw_ets_config,
+                                                 NULL);
+       if (aq_ret) {
+               dev_info(&pf->pdev->dev,
+                        "couldn't get pf vsi ets bw config, err %d, aq_err %d\n",
+                        aq_ret, pf->hw.aq.asq_last_status);
+               return -EINVAL;
+       }
+
+       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 0;
+}
+
+/**
+ * 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;
+       i40e_status aq_ret;
+       int i;
+
+       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];
+
+       aq_ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, vsi->seid, &bw_data,
+                                         NULL);
+       if (aq_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 -EINVAL;
+       }
+
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+               vsi->info.qs_handle[i] = bw_data.qs_handles[i];
+
+       return 0;
+}
+
+/**
+ * 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 48cbc833b051b3861a4568e72becf67eeaa357e4..86d51429a189295d9c7418a1273b625a933d9a9b 100644 (file)
@@ -1607,6 +1607,9 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
                        igb_write_phy_reg(hw, I347AT4_PAGE_SELECT, 0);
                        igb_write_phy_reg(hw, PHY_CONTROL, 0x4140);
                }
+       } else if (hw->phy.type == e1000_phy_82580) {
+               /* enable MII loopback */
+               igb_write_phy_reg(hw, I82580_PHY_LBK_CTRL, 0x8041);
        }
 
        /* add small delay to avoid loopback test failure */
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..ecc7f7b696b89a122b80318a12d5f6488a190126 100644 (file)
@@ -3086,23 +3086,27 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
                                               PCI_DMA_FROMDEVICE);
                skge_rx_reuse(e, skge->rx_buf_size);
        } else {
+               struct skge_element ee;
                struct sk_buff *nskb;
 
                nskb = netdev_alloc_skb_ip_align(dev, skge->rx_buf_size);
                if (!nskb)
                        goto resubmit;
 
+               ee = *e;
+
+               skb = ee.skb;
+               prefetch(skb->data);
+
                if (skge_rx_setup(skge, e, nskb, skge->rx_buf_size) < 0) {
                        dev_kfree_skb(nskb);
                        goto resubmit;
                }
 
                pci_unmap_single(skge->hw->pdev,
-                                dma_unmap_addr(e, mapaddr),
-                                dma_unmap_len(e, maplen),
+                                dma_unmap_addr(&ee, mapaddr),
+                                dma_unmap_len(&ee, 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 21962828925a5224fc122f0761eca03954e58df5..157fe8df2c3ed5c105a5301219b281670ed70efd 100644 (file)
@@ -6,13 +6,3 @@ config MLX5_CORE
        tristate
        depends on PCI && X86
        default n
-
-config MLX5_DEBUG
-       bool "Verbose debugging output" if (MLX5_CORE && EXPERT)
-       depends on MLX5_CORE
-       default y
-       ---help---
-         This option causes debugging code to be compiled into the
-         mlx5_core driver.  The output can be turned on via the
-         debug_mask module parameter (which can also be set after
-         the driver is loaded through sysfs).
index 5472cbd34028d9038539824c4167a0c3010a3a01..6ca30739625f7ac568d693b5d4b9d3d9e47b46de 100644 (file)
@@ -180,28 +180,32 @@ static int verify_block_sig(struct mlx5_cmd_prot_block *block)
        return 0;
 }
 
-static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token)
+static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token,
+                          int csum)
 {
        block->token = token;
-       block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 2);
-       block->sig = ~xor8_buf(block, sizeof(*block) - 1);
+       if (csum) {
+               block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) -
+                                           sizeof(block->data) - 2);
+               block->sig = ~xor8_buf(block, sizeof(*block) - 1);
+       }
 }
 
-static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token)
+static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token, int csum)
 {
        struct mlx5_cmd_mailbox *next = msg->next;
 
        while (next) {
-               calc_block_sig(next->buf, token);
+               calc_block_sig(next->buf, token, csum);
                next = next->next;
        }
 }
 
-static void set_signature(struct mlx5_cmd_work_ent *ent)
+static void set_signature(struct mlx5_cmd_work_ent *ent, int csum)
 {
        ent->lay->sig = ~xor8_buf(ent->lay, sizeof(*ent->lay));
-       calc_chain_sig(ent->in, ent->token);
-       calc_chain_sig(ent->out, ent->token);
+       calc_chain_sig(ent->in, ent->token, csum);
+       calc_chain_sig(ent->out, ent->token, csum);
 }
 
 static void poll_timeout(struct mlx5_cmd_work_ent *ent)
@@ -539,8 +543,7 @@ static void cmd_work_handler(struct work_struct *work)
        lay->type = MLX5_PCI_CMD_XPORT;
        lay->token = ent->token;
        lay->status_own = CMD_OWNER_HW;
-       if (!cmd->checksum_disabled)
-               set_signature(ent);
+       set_signature(ent, !cmd->checksum_disabled);
        dump_command(dev, ent, 1);
        ktime_get_ts(&ent->ts1);
 
@@ -773,8 +776,6 @@ static int mlx5_copy_from_msg(void *to, struct mlx5_cmd_msg *from, int size)
 
                copy = min_t(int, size, MLX5_CMD_DATA_BLOCK_SIZE);
                block = next->buf;
-               if (xor8_buf(block, sizeof(*block)) != 0xff)
-                       return -EINVAL;
 
                memcpy(to, block->data, copy);
                to += copy;
@@ -1361,6 +1362,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev)
                goto err_map;
        }
 
+       cmd->checksum_disabled = 1;
        cmd->max_reg_cmds = (1 << cmd->log_sz) - 1;
        cmd->bitmask = (1 << cmd->max_reg_cmds) - 1;
 
@@ -1510,7 +1512,7 @@ int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr)
        case MLX5_CMD_STAT_BAD_SYS_STATE_ERR:           return -EIO;
        case MLX5_CMD_STAT_BAD_RES_ERR:                 return -EINVAL;
        case MLX5_CMD_STAT_RES_BUSY:                    return -EBUSY;
-       case MLX5_CMD_STAT_LIM_ERR:                     return -EINVAL;
+       case MLX5_CMD_STAT_LIM_ERR:                     return -ENOMEM;
        case MLX5_CMD_STAT_BAD_RES_STATE_ERR:           return -EINVAL;
        case MLX5_CMD_STAT_IX_ERR:                      return -EINVAL;
        case MLX5_CMD_STAT_NO_RES_ERR:                  return -EAGAIN;
index 443cc4d7b024c02d2cc77861868e1c1b17ee2524..2231d93cc7ad116e55c77e0269fa27878f6c6a4d 100644 (file)
@@ -366,9 +366,11 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
                goto err_in;
        }
 
+       snprintf(eq->name, MLX5_MAX_EQ_NAME, "%s@pci:%s",
+                name, pci_name(dev->pdev));
        eq->eqn = out.eq_number;
        err = request_irq(table->msix_arr[vecidx].vector, mlx5_msix_handler, 0,
-                         name, eq);
+                         eq->name, eq);
        if (err)
                goto err_eq;
 
index b47739b0b5f6dfb34139ad74e02ac10db1d4fbbd..bc0f5fb66e249dc2e652b4126f9b907707b87c6c 100644 (file)
@@ -165,9 +165,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)
        struct mlx5_cmd_set_hca_cap_mbox_in *set_ctx = NULL;
        struct mlx5_cmd_query_hca_cap_mbox_in query_ctx;
        struct mlx5_cmd_set_hca_cap_mbox_out set_out;
-       struct mlx5_profile *prof = dev->profile;
        u64 flags;
-       int csum = 1;
        int err;
 
        memset(&query_ctx, 0, sizeof(query_ctx));
@@ -197,20 +195,14 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)
        memcpy(&set_ctx->hca_cap, &query_out->hca_cap,
               sizeof(set_ctx->hca_cap));
 
-       if (prof->mask & MLX5_PROF_MASK_CMDIF_CSUM) {
-               csum = !!prof->cmdif_csum;
-               flags = be64_to_cpu(set_ctx->hca_cap.flags);
-               if (csum)
-                       flags |= MLX5_DEV_CAP_FLAG_CMDIF_CSUM;
-               else
-                       flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM;
-
-               set_ctx->hca_cap.flags = cpu_to_be64(flags);
-       }
-
        if (dev->profile->mask & MLX5_PROF_MASK_QP_SIZE)
                set_ctx->hca_cap.log_max_qp = dev->profile->log_max_qp;
 
+       flags = be64_to_cpu(query_out->hca_cap.flags);
+       /* disable checksum */
+       flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM;
+
+       set_ctx->hca_cap.flags = cpu_to_be64(flags);
        memset(&set_out, 0, sizeof(set_out));
        set_ctx->hca_cap.log_uar_page_sz = cpu_to_be16(PAGE_SHIFT - 12);
        set_ctx->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_SET_HCA_CAP);
@@ -225,9 +217,6 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)
        if (err)
                goto query_ex;
 
-       if (!csum)
-               dev->cmd.checksum_disabled = 1;
-
 query_ex:
        kfree(query_out);
        kfree(set_ctx);
index 3a2408d448203623754d0aa87e35c16e809da43f..7b12acf210f81cd408a4b0e8a965fd4441165c9f 100644 (file)
@@ -90,6 +90,10 @@ struct mlx5_manage_pages_outbox {
        __be64                  pas[0];
 };
 
+enum {
+       MAX_RECLAIM_TIME_MSECS  = 5000,
+};
+
 static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u16 func_id)
 {
        struct rb_root *root = &dev->priv.page_root;
@@ -279,6 +283,9 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,
        int err;
        int i;
 
+       if (nclaimed)
+               *nclaimed = 0;
+
        memset(&in, 0, sizeof(in));
        outlen = sizeof(*out) + npages * sizeof(out->pas[0]);
        out = mlx5_vzalloc(outlen);
@@ -388,20 +395,25 @@ static int optimal_reclaimed_pages(void)
 
 int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev)
 {
-       unsigned long end = jiffies + msecs_to_jiffies(5000);
+       unsigned long end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS);
        struct fw_page *fwp;
        struct rb_node *p;
+       int nclaimed = 0;
        int err;
 
        do {
                p = rb_first(&dev->priv.page_root);
                if (p) {
                        fwp = rb_entry(p, struct fw_page, rb_node);
-                       err = reclaim_pages(dev, fwp->func_id, optimal_reclaimed_pages(), NULL);
+                       err = reclaim_pages(dev, fwp->func_id,
+                                           optimal_reclaimed_pages(),
+                                           &nclaimed);
                        if (err) {
                                mlx5_core_warn(dev, "failed reclaiming pages (%d)\n", err);
                                return err;
                        }
+                       if (nclaimed)
+                               end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS);
                }
                if (time_after(jiffies, end)) {
                        mlx5_core_warn(dev, "FW did not return all pages. giving up...\n");
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 83c2091c9c234bfe9ecbb4067d1396aee19f49f6..bd1a2d2bc2aebbad9612d167915fd743cf973c94 100644 (file)
@@ -543,7 +543,7 @@ static const struct of_device_id moxart_mac_match[] = {
        { }
 };
 
-struct __initdata platform_driver moxart_mac_driver = {
+static struct platform_driver moxart_mac_driver = {
        .probe  = moxart_mac_probe,
        .remove = moxart_remove,
        .driver = {
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 4d7ad0074d1c0c1eb1ef1026ab8954bd050f4071..ebe4c86e5230223f0c5465485a9812dc1a0aa3b0 100644 (file)
@@ -1794,3 +1794,11 @@ const struct ethtool_ops qlcnic_sriov_vf_ethtool_ops = {
        .set_msglevel           = qlcnic_set_msglevel,
        .get_msglevel           = qlcnic_get_msglevel,
 };
+
+const struct ethtool_ops qlcnic_ethtool_failed_ops = {
+       .get_settings           = qlcnic_get_settings,
+       .get_drvinfo            = qlcnic_get_drvinfo,
+       .set_msglevel           = qlcnic_set_msglevel,
+       .get_msglevel           = qlcnic_get_msglevel,
+       .set_dump               = qlcnic_set_dump,
+};
index c4c5023e1fdf64aed12efce219e2acb04922b142..21d00a0449a10f394fe6b02d5689c7b0ab3b95cf 100644 (file)
@@ -431,6 +431,9 @@ static void qlcnic_82xx_cancel_idc_work(struct qlcnic_adapter *adapter)
        while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
                usleep_range(10000, 11000);
 
+       if (!adapter->fw_work.work.func)
+               return;
+
        cancel_delayed_work_sync(&adapter->fw_work);
 }
 
@@ -2275,8 +2278,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                adapter->portnum = adapter->ahw->pci_func;
                err = qlcnic_start_firmware(adapter);
                if (err) {
-                       dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
-                       goto err_out_free_hw;
+                       dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n"
+                               "\t\tIf reboot doesn't help, try flashing the card\n");
+                       goto err_out_maintenance_mode;
                }
 
                qlcnic_get_multiq_capability(adapter);
@@ -2408,6 +2412,22 @@ err_out_disable_pdev:
        pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
        return err;
+
+err_out_maintenance_mode:
+       netdev->netdev_ops = &qlcnic_netdev_failed_ops;
+       SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops);
+       err = register_netdev(netdev);
+
+       if (err) {
+               dev_err(&pdev->dev, "Failed to register net device\n");
+               qlcnic_clr_all_drv_state(adapter, 0);
+               goto err_out_free_hw;
+       }
+
+       pci_set_drvdata(pdev, adapter);
+       qlcnic_add_sysfs(adapter);
+
+       return 0;
 }
 
 static void qlcnic_remove(struct pci_dev *pdev)
@@ -2518,8 +2538,16 @@ static int qlcnic_resume(struct pci_dev *pdev)
 static int qlcnic_open(struct net_device *netdev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       u32 state;
        int err;
 
+       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
+       if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD) {
+               netdev_err(netdev, "%s: Device is in FAILED state\n", __func__);
+
+               return -EIO;
+       }
+
        netif_carrier_off(netdev);
 
        err = qlcnic_attach(adapter);
@@ -3228,6 +3256,13 @@ void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, u32 key)
                return;
 
        state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
+       if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD) {
+               netdev_err(adapter->netdev, "%s: Device is in FAILED state\n",
+                          __func__);
+               qlcnic_api_unlock(adapter);
+
+               return;
+       }
 
        if (state == QLCNIC_DEV_READY) {
                QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
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 330d9a8774ad69a1d6d8e4d4f38aa87e243bf699..686f460b15022b4b2b7759ad29493a64a1f84592 100644 (file)
@@ -397,6 +397,7 @@ static int qlcnic_pci_sriov_disable(struct qlcnic_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
 
+       rtnl_lock();
        if (netif_running(netdev))
                __qlcnic_down(adapter, netdev);
 
@@ -407,12 +408,15 @@ static int qlcnic_pci_sriov_disable(struct qlcnic_adapter *adapter)
        /* After disabling SRIOV re-init the driver in default mode
           configure opmode based on op_mode of function
         */
-       if (qlcnic_83xx_configure_opmode(adapter))
+       if (qlcnic_83xx_configure_opmode(adapter)) {
+               rtnl_unlock();
                return -EIO;
+       }
 
        if (netif_running(netdev))
                __qlcnic_up(adapter, netdev);
 
+       rtnl_unlock();
        return 0;
 }
 
@@ -533,6 +537,7 @@ static int qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, int num_vfs)
                return -EIO;
        }
 
+       rtnl_lock();
        if (netif_running(netdev))
                __qlcnic_down(adapter, netdev);
 
@@ -555,6 +560,7 @@ static int qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, int num_vfs)
                __qlcnic_up(adapter, netdev);
 
 error:
+       rtnl_unlock();
        return err;
 }
 
index c6165d05cc13c3806cf60d9ac7513ffdf5832eed..019f4377307f025df8d7f93d3e473e7811f4101a 100644 (file)
@@ -1272,6 +1272,7 @@ void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
 void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
+       u32 state;
 
        if (device_create_bin_file(dev, &bin_attr_port_stats))
                dev_info(dev, "failed to create port stats sysfs entry");
@@ -1285,8 +1286,13 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
        if (device_create_bin_file(dev, &bin_attr_mem))
                dev_info(dev, "failed to create mem sysfs entry\n");
 
+       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
+       if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD)
+               return;
+
        if (device_create_bin_file(dev, &bin_attr_pci_config))
                dev_info(dev, "failed to create pci config sysfs entry");
+
        if (device_create_file(dev, &dev_attr_beacon))
                dev_info(dev, "failed to create beacon sysfs entry");
 
@@ -1307,6 +1313,7 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
 void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
+       u32 state;
 
        device_remove_bin_file(dev, &bin_attr_port_stats);
 
@@ -1315,6 +1322,11 @@ void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
        device_remove_file(dev, &dev_attr_diag_mode);
        device_remove_bin_file(dev, &bin_attr_crb);
        device_remove_bin_file(dev, &bin_attr_mem);
+
+       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
+       if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD)
+               return;
+
        device_remove_bin_file(dev, &bin_attr_pci_config);
        device_remove_file(dev, &dev_attr_beacon);
        if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
index 10093f0c4c0f3d507514da946df9047b3d68d925..6bc5db7039201a1af0a835867e900ed59ab0af13 100644 (file)
@@ -740,8 +740,8 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
        int i;
 
        if (!mpi_coredump) {
-               netif_err(qdev, drv, qdev->ndev, "No memory available\n");
-               return -ENOMEM;
+               netif_err(qdev, drv, qdev->ndev, "No memory allocated\n");
+               return -EINVAL;
        }
 
        /* Try to get the spinlock, but dont worry if
index ff2bf8a4e24773429f02e1b66777e76bdd079134..7ad146080c3649585e5c4611c6ba79883bda6293 100644 (file)
@@ -1274,7 +1274,7 @@ void ql_mpi_reset_work(struct work_struct *work)
                return;
        }
 
-       if (!ql_core_dump(qdev, qdev->mpi_coredump)) {
+       if (qdev->mpi_coredump && !ql_core_dump(qdev, qdev->mpi_coredump)) {
                netif_err(qdev, drv, qdev->ndev, "Core is dumped!\n");
                qdev->core_is_dumped = 1;
                queue_delayed_work(qdev->workqueue,
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 128d7cdf9eb207583afc36dc8706ef3503b3f5a5..c082562dbf4ee8d96388dc21e0b2da1803fe84f2 100644 (file)
 
 /* A reboot/assertion causes the MCDI status word to be set after the
  * command word is set or a REBOOT event is sent. If we notice a reboot
- * via these mechanisms then wait 20ms for the status word to be set.
+ * via these mechanisms then wait 250ms for the status word to be set.
  */
 #define MCDI_STATUS_DELAY_US           100
-#define MCDI_STATUS_DELAY_COUNT                200
+#define MCDI_STATUS_DELAY_COUNT                2500
 #define MCDI_STATUS_SLEEP_MS                                           \
        (MCDI_STATUS_DELAY_US * MCDI_STATUS_DELAY_COUNT / 1000)
 
@@ -800,9 +800,6 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
        } else {
                int count;
 
-               /* Nobody was waiting for an MCDI request, so trigger a reset */
-               efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
-
                /* Consume the status word since efx_mcdi_rpc_finish() won't */
                for (count = 0; count < MCDI_STATUS_DELAY_COUNT; ++count) {
                        if (efx_mcdi_poll_reboot(efx))
@@ -810,6 +807,9 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
                        udelay(MCDI_STATUS_DELAY_US);
                }
                mcdi->new_epoch = true;
+
+               /* Nobody was waiting for an MCDI request, so trigger a reset */
+               efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
        }
 
        spin_unlock(&mcdi->iface_lock);
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 c8f088ab5fdfdbb6c9c757f5defd9c9b70588163..bdf697b184ae14246a4173d09833367ba312d7df 100644 (file)
@@ -32,7 +32,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #define DRV_NAME       "via-rhine"
-#define DRV_VERSION    "1.5.0"
+#define DRV_VERSION    "1.5.1"
 #define DRV_RELDATE    "2010-10-09"
 
 #include <linux/types.h>
@@ -1704,7 +1704,12 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
                cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
        if (unlikely(vlan_tx_tag_present(skb))) {
-               rp->tx_ring[entry].tx_status = cpu_to_le32((vlan_tx_tag_get(skb)) << 16);
+               u16 vid_pcp = vlan_tx_tag_get(skb);
+
+               /* drop CFI/DEI bit, register needs VID and PCP */
+               vid_pcp = (vid_pcp & VLAN_VID_MASK) |
+                         ((vid_pcp & VLAN_PRIO_MASK) >> 1);
+               rp->tx_ring[entry].tx_status = cpu_to_le32((vid_pcp) << 16);
                /* request tagging */
                rp->tx_ring[entry].desc_length |= cpu_to_le32(0x020000);
        }
index b88121f240ca609ea26f911508b829c8fbbdbdd1..0029148077a9805a288a42a9d8207a97ce6e8133 100644 (file)
@@ -297,6 +297,12 @@ static int temac_dma_bd_init(struct net_device *ndev)
                       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
        lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
 
+       /* Init descriptor indexes */
+       lp->tx_bd_ci = 0;
+       lp->tx_bd_next = 0;
+       lp->tx_bd_tail = 0;
+       lp->rx_bd_ci = 0;
+
        return 0;
 
 out:
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 a34d6bf5e43b5b29325215e358cca9ee3fc734ee..cc70ecfc70626789183e462c8b51d13f0c7fc8aa 100644 (file)
@@ -429,11 +429,13 @@ static void slip_write_wakeup(struct tty_struct *tty)
        if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
                return;
 
+       spin_lock(&sl->lock);
        if (sl->xleft <= 0)  {
                /* Now serial buffer is almost free & we can start
                 * transmission of another packet */
                sl->dev->stats.tx_packets++;
                clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+               spin_unlock(&sl->lock);
                sl_unlock(sl);
                return;
        }
@@ -441,6 +443,7 @@ static void slip_write_wakeup(struct tty_struct *tty)
        actual = tty->ops->write(tty, sl->xhead, sl->xleft);
        sl->xleft -= actual;
        sl->xhead += actual;
+       spin_unlock(&sl->lock);
 }
 
 static void sl_tx_timeout(struct net_device *dev)
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 2dbb9460349d3659fc738eabb35f01cb0022e049..c6867f926cffc18a981c7682e5493ae36924d988 100644 (file)
@@ -303,7 +303,7 @@ static void dm9601_set_multicast(struct net_device *net)
                rx_ctl |= 0x02;
        } else if (net->flags & IFF_ALLMULTI ||
                   netdev_mc_count(net) > DM_MAX_MCAST) {
-               rx_ctl |= 0x04;
+               rx_ctl |= 0x08;
        } else if (!netdev_mc_empty(net)) {
                struct netdev_hw_addr *ha;
 
index 3a8131582e753074c5fa0e3b9df2cab76f0face6..3d6aaf79d8b2399565b4e9c1a64edd4fe27b90af 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)},
@@ -585,7 +714,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x2357, 0x0201, 4)},    /* TP-LINK HSUPA Modem MA180 */
        {QMI_FIXED_INTF(0x2357, 0x9000, 4)},    /* TP-LINK MA260 */
        {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)},    /* Telit LE920 */
-       {QMI_FIXED_INTF(0x1e2d, 0x12d1, 4)},    /* Cinterion PLxx */
+       {QMI_FIXED_INTF(0x1e2d, 0x0060, 4)},    /* Cinterion PLxx */
 
        /* 4. Gobi 1000 devices */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
@@ -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 7b331e613e02aec22c3ac225e3a99c53c5f0f822..bf94e10a37c8e0121d783fc54c1b565b57a7ce21 100644 (file)
@@ -1241,7 +1241,9 @@ static int build_dma_sg(const struct sk_buff *skb, struct urb *urb)
        if (num_sgs == 1)
                return 0;
 
-       urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist), GFP_ATOMIC);
+       /* reserve one for zero packet */
+       urb->sg = kmalloc((num_sgs + 1) * sizeof(struct scatterlist),
+                         GFP_ATOMIC);
        if (!urb->sg)
                return -ENOMEM;
 
@@ -1305,7 +1307,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
                if (build_dma_sg(skb, urb) < 0)
                        goto drop;
        }
-       entry->length = length = urb->transfer_buffer_length;
+       length = urb->transfer_buffer_length;
 
        /* don't assume the hardware handles USB_ZERO_PACKET
         * NOTE:  strictly conforming cdc-ether devices should expect
@@ -1317,15 +1319,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
        if (length % dev->maxpacket == 0) {
                if (!(info->flags & FLAG_SEND_ZLP)) {
                        if (!(info->flags & FLAG_MULTI_PACKET)) {
-                               urb->transfer_buffer_length++;
-                               if (skb_tailroom(skb)) {
+                               length++;
+                               if (skb_tailroom(skb) && !urb->num_sgs) {
                                        skb->data[skb->len] = 0;
                                        __skb_put(skb, 1);
-                               }
+                               } else if (urb->num_sgs)
+                                       sg_set_buf(&urb->sg[urb->num_sgs++],
+                                                       dev->padding_pkt, 1);
                        }
                } else
                        urb->transfer_flags |= URB_ZERO_PACKET;
        }
+       entry->length = urb->transfer_buffer_length = length;
 
        spin_lock_irqsave(&dev->txq.lock, flags);
        retval = usb_autopm_get_interface_async(dev->intf);
@@ -1509,6 +1514,7 @@ void usbnet_disconnect (struct usb_interface *intf)
 
        usb_kill_urb(dev->interrupt);
        usb_free_urb(dev->interrupt);
+       kfree(dev->padding_pkt);
 
        free_netdev(net);
 }
@@ -1679,9 +1685,16 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        /* initialize max rx_qlen and tx_qlen */
        usbnet_update_max_qlen(dev);
 
+       if (dev->can_dma_sg && !(info->flags & FLAG_SEND_ZLP) &&
+               !(info->flags & FLAG_MULTI_PACKET)) {
+               dev->padding_pkt = kzalloc(1, GFP_KERNEL);
+               if (!dev->padding_pkt)
+                       goto out4;
+       }
+
        status = register_netdev (net);
        if (status)
-               goto out4;
+               goto out5;
        netif_info(dev, probe, dev->net,
                   "register '%s' at usb-%s-%s, %s, %pM\n",
                   udev->dev.driver->name,
@@ -1699,6 +1712,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 
        return 0;
 
+out5:
+       kfree(dev->padding_pkt);
 out4:
        usb_free_urb(dev->interrupt);
 out3:
index bf64b4191dcc379f8d0c3d9ec287bb998efa6a69..2ef5b6219f3f46db28cb1256ce6eaa8fffc0bb3c 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) {
@@ -952,8 +952,7 @@ void vxlan_sock_release(struct vxlan_sock *vs)
 
        spin_lock(&vn->sock_lock);
        hlist_del_rcu(&vs->hlist);
-       smp_wmb();
-       vs->sock->sk->sk_user_data = NULL;
+       rcu_assign_sk_user_data(vs->sock->sk, NULL);
        vxlan_notify_del_rx_port(sk);
        spin_unlock(&vn->sock_lock);
 
@@ -1048,8 +1047,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 
        port = inet_sk(sk)->inet_sport;
 
-       smp_read_barrier_depends();
-       vs = (struct vxlan_sock *)sk->sk_user_data;
+       vs = rcu_dereference_sk_user_data(sk);
        if (!vs)
                goto drop;
 
@@ -2021,7 +2019,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 +2028,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);
@@ -2304,8 +2300,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
        atomic_set(&vs->refcnt, 1);
        vs->rcv = rcv;
        vs->data = data;
-       smp_wmb();
-       vs->sock->sk->sk_user_data = vs;
+       rcu_assign_sk_user_data(vs->sock->sk, vs);
 
        spin_lock(&vn->sock_lock);
        hlist_add_head_rcu(&vs->hlist, vs_head(net, port));
@@ -2492,15 +2487,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 4ee472a5a4e4ee6e81b1c0ffc820b6f685fb7ad1..ab9e3a8410bc2065fff9cb58996645fbf67be4fc 100644 (file)
@@ -1269,13 +1269,6 @@ static void ath9k_antenna_check(struct ath_softc *sc,
        if (!(ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB))
                return;
 
-       /*
-        * All MPDUs in an aggregate will use the same LNA
-        * as the first MPDU.
-        */
-       if (rs->rs_isaggr && !rs->rs_firstaggr)
-               return;
-
        /*
         * Change the default rx antenna if rx diversity
         * chooses the other antenna 3 times in a row.
index 35b515fe3ffa41e00dc614b6590cc2eabead9de4..5ac713d2ff5d22dc6d976291c6d97098bfbceafd 100644 (file)
@@ -399,6 +399,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
        tbf->bf_buf_addr = bf->bf_buf_addr;
        memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
        tbf->bf_state = bf->bf_state;
+       tbf->bf_state.stale = false;
 
        return tbf;
 }
@@ -1389,11 +1390,15 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
                      u16 tid, u16 *ssn)
 {
        struct ath_atx_tid *txtid;
+       struct ath_txq *txq;
        struct ath_node *an;
        u8 density;
 
        an = (struct ath_node *)sta->drv_priv;
        txtid = ATH_AN_2_TID(an, tid);
+       txq = txtid->ac->txq;
+
+       ath_txq_lock(sc, txq);
 
        /* update ampdu factor/density, they may have changed. This may happen
         * in HT IBSS when a beacon with HT-info is received after the station
@@ -1417,6 +1422,8 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
        memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf));
        txtid->baw_head = txtid->baw_tail = 0;
 
+       ath_txq_unlock_complete(sc, txq);
+
        return 0;
 }
 
@@ -1555,8 +1562,10 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
                        __skb_unlink(bf->bf_mpdu, tid_q);
                        list_add_tail(&bf->list, &bf_q);
                        ath_set_rates(tid->an->vif, tid->an->sta, bf);
-                       ath_tx_addto_baw(sc, tid, bf);
-                       bf->bf_state.bf_type &= ~BUF_AGGR;
+                       if (bf_isampdu(bf)) {
+                               ath_tx_addto_baw(sc, tid, bf);
+                               bf->bf_state.bf_type &= ~BUF_AGGR;
+                       }
                        if (bf_tail)
                                bf_tail->bf_next = bf;
 
@@ -1950,7 +1959,9 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
                        if (bf_is_ampdu_not_probing(bf))
                                txq->axq_ampdu_depth++;
 
-                       bf = bf->bf_lastbf->bf_next;
+                       bf_last = bf->bf_lastbf;
+                       bf = bf_last->bf_next;
+                       bf_last->bf_next = NULL;
                }
        }
 }
index fc8a0fa6d3b2b111d555770727b9f0a405637308..b00a7e92225f7b928f5a3cf7395f860af27299bd 100644 (file)
@@ -28,7 +28,7 @@ config BRCMFMAC
 
 config BRCMFMAC_SDIO
        bool "SDIO bus interface support for FullMAC driver"
-       depends on MMC
+       depends on (MMC = y || MMC = BRCMFMAC)
        depends on BRCMFMAC
        select FW_LOADER
        default y
@@ -39,7 +39,7 @@ config BRCMFMAC_SDIO
 
 config BRCMFMAC_USB
        bool "USB bus interface support for FullMAC driver"
-       depends on USB
+       depends on (USB = y || USB = BRCMFMAC)
        depends on BRCMFMAC
        select FW_LOADER
        ---help---
index 64f4a2bc8ddedf6c131d8b8d70408acb3ba17d9b..c3462b75bd080d4f7e9d72dd979f86bd5c894319 100644 (file)
@@ -464,8 +464,6 @@ static struct sdio_driver brcmf_sdmmc_driver = {
 
 static int brcmf_sdio_pd_probe(struct platform_device *pdev)
 {
-       int ret;
-
        brcmf_dbg(SDIO, "Enter\n");
 
        brcmfmac_sdio_pdata = pdev->dev.platform_data;
@@ -473,11 +471,7 @@ static int brcmf_sdio_pd_probe(struct platform_device *pdev)
        if (brcmfmac_sdio_pdata->power_on)
                brcmfmac_sdio_pdata->power_on();
 
-       ret = sdio_register_driver(&brcmf_sdmmc_driver);
-       if (ret)
-               brcmf_err("sdio_register_driver failed: %d\n", ret);
-
-       return ret;
+       return 0;
 }
 
 static int brcmf_sdio_pd_remove(struct platform_device *pdev)
@@ -500,6 +494,15 @@ static struct platform_driver brcmf_sdio_pd = {
        }
 };
 
+void brcmf_sdio_register(void)
+{
+       int ret;
+
+       ret = sdio_register_driver(&brcmf_sdmmc_driver);
+       if (ret)
+               brcmf_err("sdio_register_driver failed: %d\n", ret);
+}
+
 void brcmf_sdio_exit(void)
 {
        brcmf_dbg(SDIO, "Enter\n");
@@ -510,18 +513,13 @@ void brcmf_sdio_exit(void)
                sdio_unregister_driver(&brcmf_sdmmc_driver);
 }
 
-void brcmf_sdio_init(void)
+void __init brcmf_sdio_init(void)
 {
        int ret;
 
        brcmf_dbg(SDIO, "Enter\n");
 
        ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
-       if (ret == -ENODEV) {
-               brcmf_dbg(SDIO, "No platform data available, registering without.\n");
-               ret = sdio_register_driver(&brcmf_sdmmc_driver);
-       }
-
-       if (ret)
-               brcmf_err("driver registration failed: %d\n", ret);
+       if (ret == -ENODEV)
+               brcmf_dbg(SDIO, "No platform data available.\n");
 }
index f7c1985844e44c3ed0464a4e21588d538f693959..74156f84180ca19b87df7ff244358f0ab830dab3 100644 (file)
@@ -156,10 +156,11 @@ extern int brcmf_bus_start(struct device *dev);
 #ifdef CONFIG_BRCMFMAC_SDIO
 extern void brcmf_sdio_exit(void);
 extern void brcmf_sdio_init(void);
+extern void brcmf_sdio_register(void);
 #endif
 #ifdef CONFIG_BRCMFMAC_USB
 extern void brcmf_usb_exit(void);
-extern void brcmf_usb_init(void);
+extern void brcmf_usb_register(void);
 #endif
 
 #endif                         /* _BRCMF_BUS_H_ */
index e067aec1fbf113220d1a1054ca3dfceb027448a2..40e7f854e10f9634b44e4475b3c78cab02ea4dc9 100644 (file)
@@ -1231,21 +1231,23 @@ u32 brcmf_get_chip_info(struct brcmf_if *ifp)
        return bus->chip << 4 | bus->chiprev;
 }
 
-static void brcmf_driver_init(struct work_struct *work)
+static void brcmf_driver_register(struct work_struct *work)
 {
-       brcmf_debugfs_init();
-
 #ifdef CONFIG_BRCMFMAC_SDIO
-       brcmf_sdio_init();
+       brcmf_sdio_register();
 #endif
 #ifdef CONFIG_BRCMFMAC_USB
-       brcmf_usb_init();
+       brcmf_usb_register();
 #endif
 }
-static DECLARE_WORK(brcmf_driver_work, brcmf_driver_init);
+static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register);
 
 static int __init brcmfmac_module_init(void)
 {
+       brcmf_debugfs_init();
+#ifdef CONFIG_BRCMFMAC_SDIO
+       brcmf_sdio_init();
+#endif
        if (!schedule_work(&brcmf_driver_work))
                return -EBUSY;
 
index 39e01a7c8556f2ce022bd5b8c545c2e2a615af5d..f4aea47e0730996ec059f02dbc1f2edaf98c04d1 100644 (file)
@@ -1539,7 +1539,7 @@ void brcmf_usb_exit(void)
        brcmf_release_fw(&fw_image_list);
 }
 
-void brcmf_usb_init(void)
+void brcmf_usb_register(void)
 {
        brcmf_dbg(USB, "Enter\n");
        INIT_LIST_HEAD(&fw_image_list);
index 3a6544710c8ab222cc126ef53d5f19143498cc9e..edc5d105ff980e40e1ad2221a4c7686f87b0cea1 100644 (file)
@@ -457,6 +457,8 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
        if (err != 0)
                brcms_err(wl->wlc->hw->d11core, "%s: brcms_up() returned %d\n",
                          __func__, err);
+
+       bcma_core_pci_power_save(wl->wlc->hw->d11core->bus, true);
        return err;
 }
 
@@ -479,6 +481,8 @@ static void brcms_ops_stop(struct ieee80211_hw *hw)
                return;
        }
 
+       bcma_core_pci_power_save(wl->wlc->hw->d11core->bus, false);
+
        /* put driver in down state */
        spin_lock_bh(&wl->lock);
        brcms_down(wl);
index d06376014bcda61bd73d92adeac2b4bf65640883..899cad34ccd3aa1649029d90294fe21c30608d14 100644 (file)
@@ -40,6 +40,7 @@ struct hwbus_priv {
        struct cw1200_common    *core;
        const struct cw1200_platform_data_spi *pdata;
        spinlock_t              lock; /* Serialize all bus operations */
+       wait_queue_head_t       wq;
        int claimed;
 };
 
@@ -197,8 +198,11 @@ static void cw1200_spi_lock(struct hwbus_priv *self)
 {
        unsigned long flags;
 
+       DECLARE_WAITQUEUE(wait, current);
+
        might_sleep();
 
+       add_wait_queue(&self->wq, &wait);
        spin_lock_irqsave(&self->lock, flags);
        while (1) {
                set_current_state(TASK_UNINTERRUPTIBLE);
@@ -211,6 +215,7 @@ static void cw1200_spi_lock(struct hwbus_priv *self)
        set_current_state(TASK_RUNNING);
        self->claimed = 1;
        spin_unlock_irqrestore(&self->lock, flags);
+       remove_wait_queue(&self->wq, &wait);
 
        return;
 }
@@ -222,6 +227,8 @@ static void cw1200_spi_unlock(struct hwbus_priv *self)
        spin_lock_irqsave(&self->lock, flags);
        self->claimed = 0;
        spin_unlock_irqrestore(&self->lock, flags);
+       wake_up(&self->wq);
+
        return;
 }
 
@@ -243,9 +250,10 @@ static int cw1200_spi_irq_subscribe(struct hwbus_priv *self)
 
        pr_debug("SW IRQ subscribe\n");
 
-       ret = request_any_context_irq(self->func->irq, cw1200_spi_irq_handler,
-                                     IRQF_TRIGGER_HIGH,
-                                     "cw1200_wlan_irq", self);
+       ret = request_threaded_irq(self->func->irq, NULL,
+                                  cw1200_spi_irq_handler,
+                                  IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                                  "cw1200_wlan_irq", self);
        if (WARN_ON(ret < 0))
                goto exit;
 
@@ -400,6 +408,8 @@ static int cw1200_spi_probe(struct spi_device *func)
 
        spi_set_drvdata(func, self);
 
+       init_waitqueue_head(&self->wq);
+
        status = cw1200_spi_irq_subscribe(self);
 
        status = cw1200_core_probe(&cw1200_spi_hwbus_ops,
index 21c688264708316b34c51d196aa36fff5f5aaf01..1214c587fd08587f263b2c979eab9bc902b53ae1 100644 (file)
@@ -150,7 +150,7 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv,
  */
 int
 mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
-                         struct mwifiex_ra_list_tbl *pra_list, int headroom,
+                         struct mwifiex_ra_list_tbl *pra_list,
                          int ptrindex, unsigned long ra_list_flags)
                          __releases(&priv->wmm.ra_list_spinlock)
 {
@@ -160,6 +160,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
        int pad = 0, ret;
        struct mwifiex_tx_param tx_param;
        struct txpd *ptx_pd = NULL;
+       int headroom = adapter->iface_type == MWIFIEX_USB ? 0 : INTF_HEADER_LEN;
 
        skb_src = skb_peek(&pra_list->skb_head);
        if (!skb_src) {
index 900e1c62a0cceb4499457be3b76be7e9589be415..892098d6a69687dd2d8c1fc61612a6fb9999d754 100644 (file)
@@ -26,7 +26,7 @@
 int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
                                struct sk_buff *skb);
 int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
-                             struct mwifiex_ra_list_tbl *ptr, int headroom,
+                             struct mwifiex_ra_list_tbl *ptr,
                              int ptr_index, unsigned long flags)
                              __releases(&priv->wmm.ra_list_spinlock);
 
index 2d761477d15e5761ed968200484a6fd55d066f39..a6c46f3b6e3a0d622b796f094b5b75016428438e 100644 (file)
@@ -1155,7 +1155,7 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
        uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions);
 
        if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE) &&
-           adapter->iface_type == MWIFIEX_SDIO) {
+           adapter->iface_type != MWIFIEX_USB) {
                mwifiex_hs_activated_event(priv, true);
                return 0;
        } else {
@@ -1167,8 +1167,7 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
        }
        if (conditions != HS_CFG_CANCEL) {
                adapter->is_hs_configured = true;
-               if (adapter->iface_type == MWIFIEX_USB ||
-                   adapter->iface_type == MWIFIEX_PCIE)
+               if (adapter->iface_type == MWIFIEX_USB)
                        mwifiex_hs_activated_event(priv, true);
        } else {
                adapter->is_hs_configured = false;
index 2472d4b7f00e997bc9e6b21586edcf42fe692498..1c70b8d092270ba3a456664aaf6ec3e9da4b3b59 100644 (file)
@@ -447,9 +447,6 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
         */
        adapter->is_suspended = true;
 
-       for (i = 0; i < adapter->priv_num; i++)
-               netif_carrier_off(adapter->priv[i]->netdev);
-
        if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb)
                usb_kill_urb(card->rx_cmd.urb);
 
@@ -509,10 +506,6 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
                                                  MWIFIEX_RX_CMD_BUF_SIZE);
        }
 
-       for (i = 0; i < adapter->priv_num; i++)
-               if (adapter->priv[i]->media_connected)
-                       netif_carrier_on(adapter->priv[i]->netdev);
-
        /* Disable Host Sleep */
        if (adapter->hs_activated)
                mwifiex_cancel_hs(mwifiex_get_priv(adapter,
index 2e8f9cdea54d719cf0f25b4b29d816eb0709ff7a..95fa3599b4070b02aecc8d4d46073137b05c5b98 100644 (file)
@@ -1239,8 +1239,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
                if (enable_tx_amsdu && mwifiex_is_amsdu_allowed(priv, tid) &&
                    mwifiex_is_11n_aggragation_possible(priv, ptr,
                                                        adapter->tx_buf_size))
-                       mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN,
-                                                 ptr_index, flags);
+                       mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags);
                        /* ra_list_spinlock has been freed in
                           mwifiex_11n_aggregate_pkt() */
                else
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 b9deef66cf4b8179893b918fbd0fb3365480a686..e328d3058c419a0c7c4c367fd7e62ada31ddded4 100644 (file)
@@ -83,6 +83,7 @@ static struct usb_device_id p54u_table[] = {
        {USB_DEVICE(0x06a9, 0x000e)},   /* Westell 802.11g USB (A90-211WG-01) */
        {USB_DEVICE(0x06b9, 0x0121)},   /* Thomson SpeedTouch 121g */
        {USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */
+       {USB_DEVICE(0x07aa, 0x0020)},   /* Corega WLUSB2GTST USB */
        {USB_DEVICE(0x0803, 0x4310)},   /* Zoom 4410a */
        {USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */
        {USB_DEVICE(0x083a, 0x4531)},   /* T-Com Sinus 154 data II */
@@ -979,6 +980,7 @@ static int p54u_load_firmware(struct ieee80211_hw *dev,
        if (err) {
                dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
                                          "(%d)!\n", p54u_fwlist[i].fw, err);
+               usb_put_dev(udev);
        }
 
        return err;
index 95e6e61c3de0db729ec27e1eb4ce4f601faf7b1d..88ce656f96cda3d7ea1f7ae5756827538edfc6d2 100644 (file)
@@ -6659,19 +6659,20 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
                     rt2800_init_registers(rt2x00dev)))
                return -EIO;
 
+       if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev)))
+               return -EIO;
+
        /*
         * Send signal to firmware during boot time.
         */
        rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
        rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
-       if (rt2x00_is_usb(rt2x00dev)) {
+       if (rt2x00_is_usb(rt2x00dev))
                rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0);
-               rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
-       }
+       rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
        msleep(1);
 
-       if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev) ||
-                    rt2800_wait_bbp_ready(rt2x00dev)))
+       if (unlikely(rt2800_wait_bbp_ready(rt2x00dev)))
                return -EIO;
 
        rt2800_init_bbp(rt2x00dev);
index 841fb9dfc9dadcc0d25e8017c8a11ba8505486fd..9a6edb0c014ec3526c5b4c260b8784cc8fd855d0 100644 (file)
@@ -438,17 +438,16 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
                skb_queue_tail(&priv->rx_queue, skb);
                usb_anchor_urb(entry, &priv->anchored);
                ret = usb_submit_urb(entry, GFP_KERNEL);
+               usb_put_urb(entry);
                if (ret) {
                        skb_unlink(skb, &priv->rx_queue);
                        usb_unanchor_urb(entry);
                        goto err;
                }
-               usb_free_urb(entry);
        }
        return ret;
 
 err:
-       usb_free_urb(entry);
        kfree_skb(skb);
        usb_kill_anchored_urbs(&priv->anchored);
        return ret;
@@ -956,8 +955,12 @@ static int rtl8187_start(struct ieee80211_hw *dev)
                                  (RETRY_COUNT << 8  /* short retry limit */) |
                                  (RETRY_COUNT << 0  /* long retry limit */) |
                                  (7 << 21 /* MAX TX DMA */));
-               rtl8187_init_urbs(dev);
-               rtl8187b_init_status_urb(dev);
+               ret = rtl8187_init_urbs(dev);
+               if (ret)
+                       goto rtl8187_start_exit;
+               ret = rtl8187b_init_status_urb(dev);
+               if (ret)
+                       usb_kill_anchored_urbs(&priv->anchored);
                goto rtl8187_start_exit;
        }
 
@@ -966,7 +969,9 @@ static int rtl8187_start(struct ieee80211_hw *dev)
        rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0);
        rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0);
 
-       rtl8187_init_urbs(dev);
+       ret = rtl8187_init_urbs(dev);
+       if (ret)
+               goto rtl8187_start_exit;
 
        reg = RTL818X_RX_CONF_ONLYERLPKT |
              RTL818X_RX_CONF_RX_AUTORESETPHY |
index cc03e7c87cbe739c9d762a6462b1b0b6f21e1795..703258742d28eefd339bde254d30661c4175b1a9 100644 (file)
@@ -2057,7 +2057,7 @@ struct rtl_priv {
           that it points to the data allocated
           beyond  this structure like:
           rtl_pci_priv or rtl_usb_priv */
-       u8 priv[0];
+       u8 priv[0] __aligned(sizeof(void *));
 };
 
 #define rtl_priv(hw)           (((struct rtl_priv *)(hw)->priv))
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 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 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..b45bce20ad7624421b7500cff3ccfc5a49f9204f 100644 (file)
 struct backend_info {
        struct xenbus_device *dev;
        struct xenvif *vif;
+
+       /* This is the state that will be reflected in xenstore when any
+        * active hotplug script completes.
+        */
+       enum xenbus_state state;
+
        enum xenbus_state frontend_state;
        struct xenbus_watch hotplug_status_watch;
        u8 have_hotplug_status_watch:1;
@@ -42,7 +48,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);
@@ -136,6 +142,8 @@ static int netback_probe(struct xenbus_device *dev,
        if (err)
                goto fail;
 
+       be->state = XenbusStateInitWait;
+
        /* This kicks hotplug scripts, so do it immediately. */
        backend_create_xenvif(be);
 
@@ -208,15 +216,113 @@ static void backend_create_xenvif(struct backend_info *be)
        kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
 }
 
+static void backend_disconnect(struct backend_info *be)
+{
+       if (be->vif)
+               xenvif_disconnect(be->vif);
+}
 
-static void disconnect_backend(struct xenbus_device *dev)
+static void backend_connect(struct backend_info *be)
 {
-       struct backend_info *be = dev_get_drvdata(&dev->dev);
+       if (be->vif)
+               connect(be);
+}
 
-       if (be->vif) {
-               xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
-               xenvif_disconnect(be->vif);
-               be->vif = NULL;
+static inline void backend_switch_state(struct backend_info *be,
+                                       enum xenbus_state state)
+{
+       struct xenbus_device *dev = be->dev;
+
+       pr_debug("%s -> %s\n", dev->nodename, xenbus_strstate(state));
+       be->state = state;
+
+       /* If we are waiting for a hotplug script then defer the
+        * actual xenbus state change.
+        */
+       if (!be->have_hotplug_status_watch)
+               xenbus_switch_state(dev, state);
+}
+
+/* Handle backend state transitions:
+ *
+ * The backend state starts in InitWait and the following transitions are
+ * allowed.
+ *
+ * InitWait -> Connected
+ *
+ *    ^    \         |
+ *    |     \        |
+ *    |      \       |
+ *    |       \      |
+ *    |        \     |
+ *    |         \    |
+ *    |          V   V
+ *
+ *  Closed  <-> Closing
+ *
+ * The state argument specifies the eventual state of the backend and the
+ * function transitions to that state via the shortest path.
+ */
+static void set_backend_state(struct backend_info *be,
+                             enum xenbus_state state)
+{
+       while (be->state != state) {
+               switch (be->state) {
+               case XenbusStateClosed:
+                       switch (state) {
+                       case XenbusStateInitWait:
+                       case XenbusStateConnected:
+                               pr_info("%s: prepare for reconnect\n",
+                                       be->dev->nodename);
+                               backend_switch_state(be, XenbusStateInitWait);
+                               break;
+                       case XenbusStateClosing:
+                               backend_switch_state(be, XenbusStateClosing);
+                               break;
+                       default:
+                               BUG();
+                       }
+                       break;
+               case XenbusStateInitWait:
+                       switch (state) {
+                       case XenbusStateConnected:
+                               backend_connect(be);
+                               backend_switch_state(be, XenbusStateConnected);
+                               break;
+                       case XenbusStateClosing:
+                       case XenbusStateClosed:
+                               backend_switch_state(be, XenbusStateClosing);
+                               break;
+                       default:
+                               BUG();
+                       }
+                       break;
+               case XenbusStateConnected:
+                       switch (state) {
+                       case XenbusStateInitWait:
+                       case XenbusStateClosing:
+                       case XenbusStateClosed:
+                               backend_disconnect(be);
+                               backend_switch_state(be, XenbusStateClosing);
+                               break;
+                       default:
+                               BUG();
+                       }
+                       break;
+               case XenbusStateClosing:
+                       switch (state) {
+                       case XenbusStateInitWait:
+                       case XenbusStateConnected:
+                       case XenbusStateClosed:
+                               backend_switch_state(be, XenbusStateClosed);
+                               break;
+                       default:
+                               BUG();
+                       }
+                       break;
+               default:
+                       BUG();
+               }
        }
 }
 
@@ -228,42 +334,33 @@ static void frontend_changed(struct xenbus_device *dev,
 {
        struct backend_info *be = dev_get_drvdata(&dev->dev);
 
-       pr_debug("frontend state %s\n", xenbus_strstate(frontend_state));
+       pr_debug("%s -> %s\n", dev->otherend, xenbus_strstate(frontend_state));
 
        be->frontend_state = frontend_state;
 
        switch (frontend_state) {
        case XenbusStateInitialising:
-               if (dev->state == XenbusStateClosed) {
-                       pr_info("%s: prepare for reconnect\n", dev->nodename);
-                       xenbus_switch_state(dev, XenbusStateInitWait);
-               }
+               set_backend_state(be, XenbusStateInitWait);
                break;
 
        case XenbusStateInitialised:
                break;
 
        case XenbusStateConnected:
-               if (dev->state == XenbusStateConnected)
-                       break;
-               backend_create_xenvif(be);
-               if (be->vif)
-                       connect(be);
+               set_backend_state(be, XenbusStateConnected);
                break;
 
        case XenbusStateClosing:
-               if (be->vif)
-                       kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-               disconnect_backend(dev);
-               xenbus_switch_state(dev, XenbusStateClosing);
+               set_backend_state(be, XenbusStateClosing);
                break;
 
        case XenbusStateClosed:
-               xenbus_switch_state(dev, XenbusStateClosed);
+               set_backend_state(be, XenbusStateClosed);
                if (xenbus_dev_is_online(dev))
                        break;
                /* fall through if not online */
        case XenbusStateUnknown:
+               set_backend_state(be, XenbusStateClosed);
                device_unregister(&dev->dev);
                break;
 
@@ -356,7 +453,9 @@ static void hotplug_status_changed(struct xenbus_watch *watch,
        if (IS_ERR(str))
                return;
        if (len == sizeof("connected")-1 && !memcmp(str, "connected", len)) {
-               xenbus_switch_state(be->dev, XenbusStateConnected);
+               /* Complete any pending state change */
+               xenbus_switch_state(be->dev, be->state);
+
                /* Not interested in this watch anymore. */
                unregister_hotplug_status_watch(be);
        }
@@ -386,12 +485,8 @@ static void connect(struct backend_info *be)
        err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
                                   hotplug_status_changed,
                                   "%s/%s", dev->nodename, "hotplug-status");
-       if (err) {
-               /* Switch now, since we can't do a watch. */
-               xenbus_switch_state(dev, XenbusStateConnected);
-       } else {
+       if (!err)
                be->have_hotplug_status_watch = 1;
-       }
 
        netif_wake_queue(be->vif->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 e486e416d5a08303271e5af402218a26f1f93779..7d4c70f859e30687bcd0892c195f9cbfc34826dc 100644 (file)
@@ -303,10 +303,8 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
        struct device_node *cpun, *cpus;
 
        cpus = of_find_node_by_path("/cpus");
-       if (!cpus) {
-               pr_warn("Missing cpus node, bailing out\n");
+       if (!cpus)
                return NULL;
-       }
 
        for_each_child_of_node(cpus, cpun) {
                if (of_node_cmp(cpun->type, "cpu"))
@@ -1176,65 +1174,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 +1205,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 +1290,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 +1418,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 +1791,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..a4fa9ad31b8f7cfb62f45abf47ada0649d87b867 100644 (file)
@@ -11,6 +11,7 @@
 
 #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>
@@ -125,13 +126,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 +147,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 +162,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 +202,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 +239,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 +247,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 +281,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 +334,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 +360,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 +382,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 +542,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 +625,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 +634,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 +773,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
  *
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;
index e0a6514ab46c20eb902453c3b321774d1e787ba0..f6dcde22082155577b3cdf0b0f55f103e059cae6 100644 (file)
@@ -196,7 +196,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,
@@ -264,8 +264,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 +293,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 +383,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..be12fbfcae1042e90c00d192bffe46c47821b6c4 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);
 }
 
 /*
@@ -961,14 +994,16 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
 
                /*
                 * This bridge should have been registered as a hotplug function
-                * under its parent, so the context has to be there.  If not, we
-                * are in deep goo.
+                * under its parent, so the context should be there, unless the
+                * parent is going to be handled by pciehp, in which case this
+                * bridge is not interesting to us either.
                 */
                mutex_lock(&acpiphp_context_lock);
                context = acpiphp_get_context(handle);
-               if (WARN_ON(!context)) {
+               if (!context) {
                        mutex_unlock(&acpiphp_context_lock);
                        put_device(&bus->dev);
+                       pci_dev_put(bridge->pci_dev);
                        kfree(bridge);
                        return;
                }
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 7c29ee4ed0ae5559077b7b4efd69eb7ff2fd871a..b0299e6d9a3f2d1359f78454eb67e399ea6d3eb1 100644 (file)
@@ -47,6 +47,9 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
        if (event != ACPI_NOTIFY_DEVICE_WAKE || !pci_dev)
                return;
 
+       if (pci_dev->pme_poll)
+               pci_dev->pme_poll = false;
+
        if (pci_dev->current_state == PCI_D3cold) {
                pci_wakeup_event(pci_dev);
                pm_runtime_resume(&pci_dev->dev);
@@ -57,9 +60,6 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
        if (pci_dev->pme_support)
                pci_check_pme_status(pci_dev);
 
-       if (pci_dev->pme_poll)
-               pci_dev->pme_poll = false;
-
        pci_wakeup_event(pci_dev);
        pm_runtime_resume(&pci_dev->dev);
 
index e8ccf6c0f08a3d4d5a9b03aec428efddcba77c6f..bdd64b1b4817f7223fa31db19a118db5a9caaaa5 100644 (file)
@@ -1155,8 +1155,14 @@ static void pci_enable_bridge(struct pci_dev *dev)
 
        pci_enable_bridge(dev->bus->self);
 
-       if (pci_is_enabled(dev))
+       if (pci_is_enabled(dev)) {
+               if (!dev->is_busmaster) {
+                       dev_warn(&dev->dev, "driver skip pci_set_master, fix it!\n");
+                       pci_set_master(dev);
+               }
                return;
+       }
+
        retval = pci_enable_device(dev);
        if (retval)
                dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n",
index a138965c01cbc6e4029615bc080790d2338e59e2..b8fcc38c0d116a97cf2b6f4142b026f8b8f94afb 100644 (file)
@@ -490,7 +490,7 @@ exit:
  * <devicename> <state> <pinname> are values that should match the pinctrl-maps
  * <newvalue> reflects the new config and is driver dependant
  */
-static int pinconf_dbg_config_write(struct file *file,
+static ssize_t pinconf_dbg_config_write(struct file *file,
        const char __user *user_buf, size_t count, loff_t *ppos)
 {
        struct pinctrl_maps *maps_node;
@@ -508,7 +508,7 @@ static int pinconf_dbg_config_write(struct file *file,
        int i;
 
        /* Get userspace string and assure termination */
-       buf_size = min(count, (size_t)(sizeof(buf)-1));
+       buf_size = min(count, sizeof(buf) - 1);
        if (copy_from_user(buf, user_buf, buf_size))
                return -EFAULT;
        buf[buf_size] = 0;
index 2689f8d01a1e202d72f226743e0ec8bcdba2b1d8..155b1b3a0e7a71597d26d3c0c1cab2a525a9ee19 100644 (file)
@@ -663,18 +663,18 @@ static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
 /* pin banks of s5pv210 pin-controller */
 static struct samsung_pin_bank s5pv210_pin_bank[] = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpa1", 0x04),
        EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
        EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c),
        EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10),
        EXYNOS_PIN_BANK_EINTG(4, 0x0a0, "gpd0", 0x14),
-       EXYNOS_PIN_BANK_EINTG(4, 0x0c0, "gpd1", 0x18),
-       EXYNOS_PIN_BANK_EINTG(5, 0x0e0, "gpe0", 0x1c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe1", 0x20),
-       EXYNOS_PIN_BANK_EINTG(6, 0x120, "gpf0", 0x24),
+       EXYNOS_PIN_BANK_EINTG(6, 0x0c0, "gpd1", 0x18),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpe0", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(5, 0x100, "gpe1", 0x20),
+       EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpf0", 0x24),
        EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpf1", 0x28),
        EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpf2", 0x2c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf3", 0x30),
+       EXYNOS_PIN_BANK_EINTG(6, 0x180, "gpf3", 0x30),
        EXYNOS_PIN_BANK_EINTG(7, 0x1a0, "gpg0", 0x34),
        EXYNOS_PIN_BANK_EINTG(7, 0x1c0, "gpg1", 0x38),
        EXYNOS_PIN_BANK_EINTG(7, 0x1e0, "gpg2", 0x3c),
index 82638fac3cfa6a3f40c6ce1f423d3146a5b29e02..30c4d356cb33510a550aec1d467ac40936552a60 100644 (file)
@@ -891,9 +891,10 @@ static int palmas_pinconf_set(struct pinctrl_dev *pctldev,
                param = pinconf_to_config_param(configs[i]);
                param_val = pinconf_to_config_argument(configs[i]);
 
+               if (param == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+                       continue;
+
                switch (param) {
-               case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
-                       return 0;
                case PIN_CONFIG_BIAS_DISABLE:
                case PIN_CONFIG_BIAS_PULL_UP:
                case PIN_CONFIG_BIAS_PULL_DOWN:
index 622c4854977e63471b6e77cd950184a3dd3f13f8..93c9e3899d5e4a0230e91a7269c68b7d7d8433f4 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2012-2013, NVIDIA CORPORATION.  All rights reserved.
  *
- * Arthur:  Pritesh Raithatha <praithatha@nvidia.com>
+ * Author:  Pritesh Raithatha <praithatha@nvidia.com>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -2763,7 +2763,6 @@ static struct platform_driver tegra114_pinctrl_driver = {
 };
 module_platform_driver(tegra114_pinctrl_driver);
 
-MODULE_ALIAS("platform:tegra114-pinctrl");
 MODULE_AUTHOR("Pritesh Raithatha <praithatha@nvidia.com>");
-MODULE_DESCRIPTION("NVIDIA Tegra114 pincontrol driver");
+MODULE_DESCRIPTION("NVIDIA Tegra114 pinctrl driver");
 MODULE_LICENSE("GPL v2");
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 1a78163907734be9e1e49bd3bca6e2fc19e7b6c7..b9f2653e4ef90f315de25752fe24821a98497848 100644 (file)
@@ -709,7 +709,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
                struct of_regulator_match **da9063_reg_matches)
 {
        da9063_reg_matches = NULL;
-       return PTR_ERR(-ENODEV);
+       return ERR_PTR(-ENODEV);
 }
 #endif
 
index 488dfe7ce9a6c048a751029451df59d6f6f2c074..7e2b165972e6edd6e3eee6b26478cb263db5d048 100644 (file)
@@ -201,13 +201,7 @@ static unsigned int palmas_smps_ramp_delay[4] = {0, 10000, 5000, 2500};
 #define SMPS_CTRL_MODE_ECO             0x02
 #define SMPS_CTRL_MODE_PWM             0x03
 
-/* These values are derived from the data sheet. And are the number of steps
- * where there is a voltage change, the ranges at beginning and end of register
- * max/min values where there are no change are ommitted.
- *
- * So they are basically (maxV-minV)/stepV
- */
-#define PALMAS_SMPS_NUM_VOLTAGES       117
+#define PALMAS_SMPS_NUM_VOLTAGES       122
 #define PALMAS_SMPS10_NUM_VOLTAGES     2
 #define PALMAS_LDO_NUM_VOLTAGES                50
 
@@ -979,6 +973,7 @@ static int palmas_regulators_probe(struct platform_device *pdev)
                        pmic->desc[id].min_uV = 900000;
                        pmic->desc[id].uV_step = 50000;
                        pmic->desc[id].linear_min_sel = 1;
+                       pmic->desc[id].enable_time = 500;
                        pmic->desc[id].vsel_reg =
                                        PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
                                                palmas_regs_info[id].vsel_addr);
@@ -997,6 +992,11 @@ static int palmas_regulators_probe(struct platform_device *pdev)
                                pmic->desc[id].min_uV = 450000;
                                pmic->desc[id].uV_step = 25000;
                        }
+
+                       /* LOD6 in vibrator mode will have enable time 2000us */
+                       if (pdata && pdata->ldo6_vibrator &&
+                               (id == PALMAS_REG_LDO6))
+                               pmic->desc[id].enable_time = 2000;
                } else {
                        pmic->desc[id].n_voltages = 1;
                        pmic->desc[id].ops = &palmas_ops_extreg;
index d8e3e1262bc2960b4eebf89b5c552ef6e04df305..20c271d49dcbbd358e03d5140d05e9da4ca54952 100644 (file)
@@ -279,8 +279,12 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
        ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, regs->control_reg,
                   abb->base);
 
-       /* program LDO VBB vset override if needed */
-       if (abb->ldo_base)
+       /*
+        * program LDO VBB vset override if needed for !bypass mode
+        * XXX: Do not switch sequence - for !bypass, LDO override reset *must*
+        * be performed *before* switch to bias mode else VBB glitches.
+        */
+       if (abb->ldo_base && info->opp_sel != TI_ABB_NOMINAL_OPP)
                ti_abb_program_ldovbb(dev, abb, info);
 
        /* Initiate ABB ldo change */
@@ -295,6 +299,14 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
        if (ret)
                goto out;
 
+       /*
+        * Reset LDO VBB vset override bypass mode
+        * XXX: Do not switch sequence - for bypass, LDO override reset *must*
+        * be performed *after* switch to bypass else VBB glitches.
+        */
+       if (abb->ldo_base && info->opp_sel == TI_ABB_NOMINAL_OPP)
+               ti_abb_program_ldovbb(dev, abb, info);
+
 out:
        return ret;
 }
index 1432b26ef2e97b0830a2ecf973789ee20b7991cc..2205fbc2c37b4cf9b917bafa5d1f583f7e767b49 100644 (file)
@@ -63,7 +63,7 @@ static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data)
  */
 
 static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = {
-       { .min_uV =  900000, .max_uV = 1650000, .min_sel =  0, .max_sel = 14,
+       { .min_uV =  900000, .max_uV = 1600000, .min_sel =  0, .max_sel = 14,
          .uV_step =  50000 },
        { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31,
          .uV_step = 100000 },
@@ -332,7 +332,7 @@ static struct platform_driver wm831x_gp_ldo_driver = {
  */
 
 static const struct regulator_linear_range wm831x_aldo_ranges[] = {
-       { .min_uV = 1000000, .max_uV = 1650000, .min_sel =  0, .max_sel = 12,
+       { .min_uV = 1000000, .max_uV = 1600000, .min_sel =  0, .max_sel = 12,
          .uV_step =  50000 },
        { .min_uV = 1700000, .max_uV = 3500000, .min_sel = 13, .max_sel = 31,
          .uV_step = 100000 },
index 835b5f0f344ed2537115b1ed486d14860f88434e..61ca9292a42944229f9f52bc6f5b8943b6414b22 100644 (file)
@@ -543,7 +543,7 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
 }
 
 static const struct regulator_linear_range wm8350_ldo_ranges[] = {
-       { .min_uV =  900000, .max_uV = 1750000, .min_sel =  0, .max_sel = 15,
+       { .min_uV =  900000, .max_uV = 1650000, .min_sel =  0, .max_sel = 15,
          .uV_step =  50000 },
        { .min_uV = 1800000, .max_uV = 3300000, .min_sel = 16, .max_sel = 31,
          .uV_step = 100000 },
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 8cd34bf644b3ee4b34065814fab4300774c8ad23..77df9cb00688feeda6cad1fbfd4623fc5a26134e 100644 (file)
@@ -145,9 +145,11 @@ bool __init sclp_has_linemode(void)
 
        if (sccb->header.response_code != 0x20)
                return 0;
-       if (sccb->sclp_send_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))
-               return 1;
-       return 0;
+       if (!(sccb->sclp_send_mask & (EVTYP_OPCMD_MASK | EVTYP_PMSGCMD_MASK)))
+               return 0;
+       if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)))
+               return 0;
+       return 1;
 }
 
 bool __init sclp_has_vt220(void)
index cee69dac3e182b6e2de94300b49ac9ec35658430..3f4ca4e09a4ccc4d49fba39d64094fafe1f1fdc7 100644 (file)
@@ -810,7 +810,7 @@ static void tty3270_resize_work(struct work_struct *work)
        struct winsize ws;
 
        screen = tty3270_alloc_screen(tp->n_rows, tp->n_cols);
-       if (!screen)
+       if (IS_ERR(screen))
                return;
        /* Switch to new output size */
        spin_lock_bh(&tp->view.lock);
@@ -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 fd7cc566095a40cb22d27519726c4faa14a5f37d..d4ac60b4a56e8a6f4615fcac50015a06cccd53fc 100644 (file)
@@ -1583,7 +1583,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
        /* Initialize the hardware */
        ret = clk_prepare_enable(clk);
        if (ret)
-               goto out_unmap_regs;
+               goto out_free_irq;
        spi_writel(as, CR, SPI_BIT(SWRST));
        spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
        if (as->caps.has_wdrbt) {
@@ -1614,6 +1614,7 @@ out_free_dma:
        spi_writel(as, CR, SPI_BIT(SWRST));
        spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
        clk_disable_unprepare(clk);
+out_free_irq:
        free_irq(irq, master);
 out_unmap_regs:
        iounmap(as->regs);
index 5655acf55bfe35a7d4f0fcb853e56435b4e847c9..6416798828e72bc9f5194282f55cf49a37f6809c 100644 (file)
@@ -226,7 +226,6 @@ static int spi_clps711x_probe(struct platform_device *pdev)
                               dev_name(&pdev->dev), hw);
        if (ret) {
                dev_err(&pdev->dev, "Can't request IRQ\n");
-               clk_put(hw->spi_clk);
                goto clk_out;
        }
 
@@ -247,7 +246,6 @@ err_out:
                        gpio_free(hw->chipselect[i]);
 
        spi_master_put(master);
-       kfree(master);
 
        return ret;
 }
@@ -263,7 +261,6 @@ static int spi_clps711x_remove(struct platform_device *pdev)
                        gpio_free(hw->chipselect[i]);
 
        spi_unregister_master(master);
-       kfree(master);
 
        return 0;
 }
index 6cd07d13ecab3b5fc78c263cb6220a3b0ae4ddb5..4e44575bd87a9674c72338cafe25c1b5006ef529 100644 (file)
@@ -476,15 +476,9 @@ static int dspi_probe(struct platform_device *pdev)
        master->bus_num = bus_num;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "can't get platform resource\n");
-               ret = -EINVAL;
-               goto out_master_put;
-       }
-
        dspi->base = devm_ioremap_resource(&pdev->dev, res);
-       if (!dspi->base) {
-               ret = -EINVAL;
+       if (IS_ERR(dspi->base)) {
+               ret = PTR_ERR(dspi->base);
                goto out_master_put;
        }
 
index dbc5e999a1f5689c1a526ace9f3dc4061f924223..6adf4e35816d76c1c7f120cd924420c4c8bf71a1 100644 (file)
@@ -522,8 +522,10 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
        psc_num = master->bus_num;
        snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
        clk = devm_clk_get(dev, clk_name);
-       if (IS_ERR(clk))
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
                goto free_irq;
+       }
        ret = clk_prepare_enable(clk);
        if (ret)
                goto free_irq;
index 2eb06ee0b3264020d040c2b1ea8bd6745656c372..c1a50674c1e359deb3e83fc2a04c9acf2324f58d 100644 (file)
@@ -546,8 +546,17 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
        if (pm_runtime_suspended(&drv_data->pdev->dev))
                return IRQ_NONE;
 
-       sccr1_reg = read_SSCR1(reg);
+       /*
+        * If the device is not yet in RPM suspended state and we get an
+        * interrupt that is meant for another device, check if status bits
+        * are all set to one. That means that the device is already
+        * powered off.
+        */
        status = read_SSSR(reg);
+       if (status == ~0)
+               return IRQ_NONE;
+
+       sccr1_reg = read_SSCR1(reg);
 
        /* Ignore possible writes if we don't need to write */
        if (!(sccr1_reg & SSCR1_TIE))
index 512b8893893bd3d8349506fde7785e29591236e2..a80376dc3a102d04684f27934a42412be3e851d7 100644 (file)
@@ -1428,6 +1428,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
               S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN,
               sdd->regs + S3C64XX_SPI_INT_EN);
 
+       pm_runtime_enable(&pdev->dev);
+
        if (spi_register_master(master)) {
                dev_err(&pdev->dev, "cannot register SPI master\n");
                ret = -EBUSY;
@@ -1440,8 +1442,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
                                        mem_res,
                                        sdd->rx_dma.dmach, sdd->tx_dma.dmach);
 
-       pm_runtime_enable(&pdev->dev);
-
        return 0;
 
 err3:
index 0b68cb592fa4d022bb6d3b3bc70296bcb224284b..e488a90a98b8acbfff5b1fd72dd92b54db2ae602 100644 (file)
@@ -296,6 +296,8 @@ static int hspi_probe(struct platform_device *pdev)
                goto error1;
        }
 
+       pm_runtime_enable(&pdev->dev);
+
        master->num_chipselect  = 1;
        master->bus_num         = pdev->id;
        master->setup           = hspi_setup;
@@ -309,8 +311,6 @@ static int hspi_probe(struct platform_device *pdev)
                goto error1;
        }
 
-       pm_runtime_enable(&pdev->dev);
-
        return 0;
 
  error1:
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 a84aab47a11315b137d370a9337a8f5d722bb644..f73287eab373a92b7f1a9876c3e53eb7f2cee327 100644 (file)
@@ -96,6 +96,15 @@ config COMEDI_SKEL
          To compile this driver as a module, choose M here: the module will be
          called skel.
 
+config COMEDI_SSV_DNP
+       tristate "SSV Embedded Systems DIL/Net-PC support"
+       depends on X86_32 || COMPILE_TEST
+       ---help---
+         Enable support for SSV Embedded Systems DIL/Net-PC
+
+         To compile this driver as a module, choose M here: the module will be
+         called ssv_dnp.
+
 endif # COMEDI_MISC_DRIVERS
 
 menuconfig COMEDI_ISA_DRIVERS
@@ -386,6 +395,14 @@ config COMEDI_DMM32AT
          To compile this driver as a module, choose M here: the module will be
          called dmm32at.
 
+config COMEDI_UNIOXX5
+       tristate "Fastwel UNIOxx-5 analog and digital io board support"
+       ---help---
+         Enable support for Fastwel UNIOxx-5 (analog and digital i/o) boards
+
+         To compile this driver as a module, choose M here: the module will be
+         called unioxx5.
+
 config COMEDI_FL512
        tristate "FL512 ISA card support"
        ---help---
@@ -855,14 +872,6 @@ config COMEDI_DYNA_PCI10XX
          To compile this driver as a module, choose M here: the module will be
          called dyna_pci10xx.
 
-config COMEDI_UNIOXX5
-       tristate "Fastwel UNIOxx-5 analog and digital io board support"
-       ---help---
-         Enable support for Fastwel UNIOxx-5 (analog and digital i/o) boards
-
-         To compile this driver as a module, choose M here: the module will be
-         called unioxx5.
-
 config COMEDI_GSC_HPDI
        tristate "General Standards PCI-HPDI32 / PMC-HPDI32 support"
        select COMEDI_FC
@@ -1085,14 +1094,6 @@ config COMEDI_S626
          To compile this driver as a module, choose M here: the module will be
          called s626.
 
-config COMEDI_SSV_DNP
-       tristate "SSV Embedded Systems DIL/Net-PC support"
-       ---help---
-         Enable support for SSV Embedded Systems DIL/Net-PC
-
-         To compile this driver as a module, choose M here: the module will be
-         called ssv_dnp.
-
 config COMEDI_MITE
        depends on HAS_DMA
        tristate
index 3ba4c5712dffe5c9277bab3a0a59933e2b5a7c59..853f62b2b1a982c70ba229f94b4697c9d1e869d3 100644 (file)
@@ -369,28 +369,23 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
 {
        const struct ni_65xx_board *board = comedi_board(dev);
        struct ni_65xx_private *devpriv = dev->private;
-       unsigned base_bitfield_channel;
-       const unsigned max_ports_per_bitfield = 5;
+       int base_bitfield_channel;
        unsigned read_bits = 0;
-       unsigned j;
+       int last_port_offset = ni_65xx_port_by_channel(s->n_chan - 1);
+       int port_offset;
 
        base_bitfield_channel = CR_CHAN(insn->chanspec);
-       for (j = 0; j < max_ports_per_bitfield; ++j) {
-               const unsigned port_offset =
-                       ni_65xx_port_by_channel(base_bitfield_channel) + j;
-               const unsigned port =
-                       sprivate(s)->base_port + port_offset;
-               unsigned base_port_channel;
+       for (port_offset = ni_65xx_port_by_channel(base_bitfield_channel);
+            port_offset <= last_port_offset; port_offset++) {
+               unsigned port = sprivate(s)->base_port + port_offset;
+               int base_port_channel = port_offset * ni_65xx_channels_per_port;
                unsigned port_mask, port_data, port_read_bits;
-               int bitshift;
-               if (port >= ni_65xx_total_num_ports(board))
+               int bitshift = base_port_channel - base_bitfield_channel;
+
+               if (bitshift >= 32)
                        break;
-               base_port_channel = port_offset * ni_65xx_channels_per_port;
                port_mask = data[0];
                port_data = data[1];
-               bitshift = base_port_channel - base_bitfield_channel;
-               if (bitshift >= 32 || bitshift <= -32)
-                       break;
                if (bitshift > 0) {
                        port_mask >>= bitshift;
                        port_data >>= bitshift;
index 724a685753dd8671fba84c9f3e14174164696e64..40ef785a04284d9a4c79633f2877a957b8c405dc 100644 (file)
@@ -474,7 +474,7 @@ static void dgap_cleanup_board(struct board_t *brd)
 
                 DGAP_LOCK(dgap_global_lock, flags);
                 brd->msgbuf = NULL;
-                printk(brd->msgbuf_head);
+                printk("%s", brd->msgbuf_head);
                 kfree(brd->msgbuf_head);
                 brd->msgbuf_head = NULL;
                 DGAP_UNLOCK(dgap_global_lock, flags);
@@ -628,7 +628,7 @@ static int dgap_found_board(struct pci_dev *pdev, int id)
        DPR_INIT(("dgap_scan(%d) - printing out the msgbuf\n", i));
        DGAP_LOCK(dgap_global_lock, flags);
        brd->msgbuf = NULL;
-       printk(brd->msgbuf_head);
+       printk("%s", brd->msgbuf_head);
        kfree(brd->msgbuf_head);
        brd->msgbuf_head = NULL;
        DGAP_UNLOCK(dgap_global_lock, flags);
@@ -955,25 +955,28 @@ static void dgap_mbuf(struct board_t *brd, const char *fmt, ...) {
        char            buf[1024];
        int             i;
        unsigned long   flags;
+       size_t          length;
 
        DGAP_LOCK(dgap_global_lock, flags);
 
        /* Format buf using fmt and arguments contained in ap. */
        va_start(ap, fmt);
-       i = vsprintf(buf, fmt,  ap);
+       i = vsnprintf(buf, sizeof(buf), fmt,  ap);
        va_end(ap);
 
        DPR((buf));
 
        if (!brd || !brd->msgbuf) {
-               printk(buf);
+               printk("%s", buf);
                DGAP_UNLOCK(dgap_global_lock, flags);
                return;
        }
 
-       memcpy(brd->msgbuf, buf, strlen(buf));
-       brd->msgbuf += strlen(buf);
-       *brd->msgbuf = 0;
+       length = strlen(buf) + 1;
+       if (brd->msgbuf - brd->msgbuf_head < length)
+               length = brd->msgbuf - brd->msgbuf_head;
+       memcpy(brd->msgbuf, buf, length);
+       brd->msgbuf += length;
 
        DGAP_UNLOCK(dgap_global_lock, flags);
 }
index f8c1e22585d6cf81f3a4a52262b73608ab68f333..71d2b83cc3a12e365823df2e40fd176ac26120ef 100644 (file)
@@ -454,7 +454,7 @@ static void dgnc_cleanup_board(struct board_t *brd)
 
                DGNC_LOCK(dgnc_global_lock, flags);
                brd->msgbuf = NULL;
-               printk(brd->msgbuf_head);
+               printk("%s", brd->msgbuf_head);
                kfree(brd->msgbuf_head);
                brd->msgbuf_head = NULL;
                DGNC_UNLOCK(dgnc_global_lock, flags);
@@ -710,7 +710,7 @@ static int dgnc_found_board(struct pci_dev *pdev, int id)
        DPR_INIT(("dgnc_scan(%d) - printing out the msgbuf\n", i));
        DGNC_LOCK(dgnc_global_lock, flags);
        brd->msgbuf = NULL;
-       printk(brd->msgbuf_head);
+       printk("%s", brd->msgbuf_head);
        kfree(brd->msgbuf_head);
        brd->msgbuf_head = NULL;
        DGNC_UNLOCK(dgnc_global_lock, flags);
index db4d6dc032432cf0d92ff71d6c38e52dff17ce13..b36feb080cba886f8ebf9a456c519247376dbdcb 100644 (file)
@@ -37,7 +37,7 @@ config IIO_SIMPLE_DUMMY_EVENTS
 
 config IIO_SIMPLE_DUMMY_BUFFER
        boolean "Buffered capture support"
-       depends on IIO_KFIFO_BUF
+       select IIO_KFIFO_BUF
        help
          Add buffered data capture to the simple dummy driver.
 
index 351936c3efd698e8c5cbe76d7878eb8ad16c311f..e4998e4d4434b2af9365aacc1a8c4137a4c70544 100644 (file)
@@ -563,6 +563,7 @@ static int isl29018_probe(struct i2c_client *client,
        mutex_init(&chip->lock);
 
        chip->lux_scale = 1;
+       chip->lux_uscale = 0;
        chip->range = 1000;
        chip->adc_bit = 16;
        chip->suspended = false;
index d2748c329eae6728b9c88c6b3a63065982d78555..c3f3f539e787e926b54f793958d8e9dac13aa6d7 100644 (file)
@@ -229,7 +229,7 @@ static int hmc5843_read_measurement(struct iio_dev *indio_dev,
        if (result < 0)
                return -EINVAL;
 
-       *val = result;
+       *val = sign_extend32(result, 15);
        return IIO_VAL_INT;
 }
 
index a802cf2491d61a6d55f95c6e6825792905fa118a..4c6d2041260bed259f7cba174c64ceb9a9c1a3f8 100644 (file)
@@ -299,7 +299,7 @@ static int ade7854_spi_probe(struct spi_device *spi)
        if (ret)
                iio_device_free(indio_dev);
 
-       return 0;
+       return ret;
 }
 
 static int ade7854_spi_remove(struct spi_device *spi)
index 47c5888461ffbeb3f4aa994af5b2418df6506e60..a2e52a0c53c981690dc7b711a1a97625c01a9a0f 100644 (file)
@@ -41,7 +41,6 @@ struct imx_drm_device {
        struct list_head                        encoder_list;
        struct list_head                        connector_list;
        struct mutex                            mutex;
-       int                                     references;
        int                                     pipes;
        struct drm_fbdev_cma                    *fbhelper;
 };
@@ -241,8 +240,6 @@ struct drm_device *imx_drm_device_get(void)
                }
        }
 
-       imxdrm->references++;
-
        return imxdrm->drm;
 
 unwind_crtc:
@@ -280,8 +277,6 @@ void imx_drm_device_put(void)
        list_for_each_entry(enc, &imxdrm->encoder_list, list)
                module_put(enc->owner);
 
-       imxdrm->references--;
-
        mutex_unlock(&imxdrm->mutex);
 }
 EXPORT_SYMBOL_GPL(imx_drm_device_put);
@@ -485,7 +480,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 
        mutex_lock(&imxdrm->mutex);
 
-       if (imxdrm->references) {
+       if (imxdrm->drm->open_count) {
                ret = -EBUSY;
                goto err_busy;
        }
@@ -564,7 +559,7 @@ int imx_drm_add_encoder(struct drm_encoder *encoder,
 
        mutex_lock(&imxdrm->mutex);
 
-       if (imxdrm->references) {
+       if (imxdrm->drm->open_count) {
                ret = -EBUSY;
                goto err_busy;
        }
@@ -709,7 +704,7 @@ int imx_drm_add_connector(struct drm_connector *connector,
 
        mutex_lock(&imxdrm->mutex);
 
-       if (imxdrm->references) {
+       if (imxdrm->drm->open_count) {
                ret = -EBUSY;
                goto err_busy;
        }
index 2f44d56700af1eabe13625777b3cc3ce8c94cf20..776d3632dc7d52988738b105d648161b2e99b9a2 100644 (file)
@@ -244,13 +244,17 @@ static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
        struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
        struct usb_line6_toneport *toneport =
            (struct usb_line6_toneport *)line6pcm->line6;
+       unsigned int source;
 
-       if (ucontrol->value.enumerated.item[0] == toneport->source)
+       source = ucontrol->value.enumerated.item[0];
+       if (source >= ARRAY_SIZE(toneport_source_info))
+               return -EINVAL;
+       if (source == toneport->source)
                return 0;
 
-       toneport->source = ucontrol->value.enumerated.item[0];
+       toneport->source = source;
        toneport_send_cmd(toneport->line6.usbdev,
-                         toneport_source_info[toneport->source].code, 0x0000);
+                         toneport_source_info[source].code, 0x0000);
        return 1;
 }
 
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 086ca3d7241b2b756a650bc647ab9450461f1a4a..26b49a24b3dfe32997e7d37cb479f2d98b91ce82 100644 (file)
@@ -1802,7 +1802,7 @@ kiblnd_recv (lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed,
 int
 kiblnd_thread_start(int (*fn)(void *arg), void *arg, char *name)
 {
-       struct task_struct *task = kthread_run(fn, arg, name);
+       struct task_struct *task = kthread_run(fn, arg, "%s", name);
 
        if (IS_ERR(task))
                return PTR_ERR(task);
index 2c581b7fa8adee363d19791007f4696e9e439d06..68a4f52ec998c14795d6f356e807b798c2dfa794 100644 (file)
@@ -1005,7 +1005,7 @@ ksocknal_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg)
 int
 ksocknal_thread_start(int (*fn)(void *arg), void *arg, char *name)
 {
-       struct task_struct *task = kthread_run(fn, arg, name);
+       struct task_struct *task = kthread_run(fn, arg, "%s", name);
 
        if (IS_ERR(task))
                return PTR_ERR(task);
index 4e898e4918605bf058554d6cae15b6a5e31e550a..2156a44d07409c0501cba726ccb33ee99d1d9c92 100644 (file)
@@ -1,6 +1,6 @@
 config LUSTRE_FS
        tristate "Lustre file system client support"
-       depends on INET && m
+       depends on INET && m && !MIPS && !XTENSA && !SUPERH
        select LNET
        select CRYPTO
        select CRYPTO_CRC32
@@ -52,7 +52,7 @@ config LUSTRE_DEBUG_EXPENSIVE_CHECK
 config LUSTRE_TRANSLATE_ERRNOS
        bool
        depends on LUSTRE_FS && !X86
-       default true
+       default y
 
 config LUSTRE_LLITE_LLOOP
        bool "Lustre virtual block device"
index 3916bda3004cf23c7fa58c7e51de5e621909cfc5..a100a0b96381d6ef0a55242c969ab41b7adb05be 100644 (file)
@@ -800,9 +800,9 @@ static int ldlm_bl_thread_start(struct ldlm_bl_pool *blp)
 
        init_completion(&bltd.bltd_comp);
        bltd.bltd_num = atomic_read(&blp->blp_num_threads);
-       snprintf(bltd.bltd_name, sizeof(bltd.bltd_name) - 1,
+       snprintf(bltd.bltd_name, sizeof(bltd.bltd_name),
                "ldlm_bl_%02d", bltd.bltd_num);
-       task = kthread_run(ldlm_bl_thread_main, &bltd, bltd.bltd_name);
+       task = kthread_run(ldlm_bl_thread_main, &bltd, "%s", bltd.bltd_name);
        if (IS_ERR(task)) {
                CERROR("cannot start LDLM thread ldlm_bl_%02d: rc %ld\n",
                       atomic_read(&blp->blp_num_threads), PTR_ERR(task));
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 462172d1a7569a74c1ffbae3dd0c0f133574aa2e..1a55c81892e0e8f692c167d17f0296814ad806dc 100644 (file)
@@ -397,7 +397,7 @@ cfs_wi_sched_create(char *name, struct cfs_cpt_table *cptab,
                                 sched->ws_name, sched->ws_nthreads);
                }
 
-               task = kthread_run(cfs_wi_scheduler, sched, name);
+               task = kthread_run(cfs_wi_scheduler, sched, "%s", name);
                if (!IS_ERR(task)) {
                        nthrs--;
                        continue;
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 2644edf438c1e175b016a54e96b6d93bd5852cc7..c8b43442dc74be8c8cf1ee3f5b38470f63617e71 100644 (file)
@@ -1387,7 +1387,7 @@ echo_copyout_lsm (struct lov_stripe_md *lsm, void *_ulsm, int ulsm_nob)
        if (nob > ulsm_nob)
                return (-EINVAL);
 
-       if (copy_to_user (ulsm, lsm, sizeof(ulsm)))
+       if (copy_to_user (ulsm, lsm, sizeof(*ulsm)))
                return (-EFAULT);
 
        for (i = 0; i < lsm->lsm_stripe_count; i++) {
index 227a0ae9593bc987d6bfbcf1757bc0a9eacf2288..5dec771d70eee8c08a6bc0b787f7f116ddd6906d 100644 (file)
@@ -383,8 +383,8 @@ int ptlrpc_start_pinger(void)
 
        /* CLONE_VM and CLONE_FILES just avoid a needless copy, because we
         * just drop the VM and FILES in cfs_daemonize_ctxt() right away. */
-       rc = PTR_ERR(kthread_run(ptlrpc_pinger_main,
-                                &pinger_thread, pinger_thread.t_name));
+       rc = PTR_ERR(kthread_run(ptlrpc_pinger_main, &pinger_thread,
+                                "%s", pinger_thread.t_name));
        if (IS_ERR_VALUE(rc)) {
                CERROR("cannot start thread: %d\n", rc);
                return rc;
index fbdeff65d059df66f057cec95f729a5d3ad6ad63..89c9be96f454a57c4dd0839cf92f378883dce91e 100644 (file)
@@ -615,7 +615,7 @@ int ptlrpcd_start(int index, int max, const char *name, struct ptlrpcd_ctl *pc)
        init_completion(&pc->pc_starting);
        init_completion(&pc->pc_finishing);
        spin_lock_init(&pc->pc_lock);
-       strncpy(pc->pc_name, name, sizeof(pc->pc_name) - 1);
+       strlcpy(pc->pc_name, name, sizeof(pc->pc_name));
        pc->pc_set = ptlrpc_prep_set();
        if (pc->pc_set == NULL)
                GOTO(out, rc = -ENOMEM);
@@ -638,7 +638,7 @@ int ptlrpcd_start(int index, int max, const char *name, struct ptlrpcd_ctl *pc)
                                GOTO(out, rc);
                }
 
-               task = kthread_run(ptlrpcd, pc, pc->pc_name);
+               task = kthread_run(ptlrpcd, pc, "%s", pc->pc_name);
                if (IS_ERR(task))
                        GOTO(out, rc = PTR_ERR(task));
 
@@ -745,7 +745,7 @@ static int ptlrpcd_init(void)
        if (ptlrpcds == NULL)
                GOTO(out, rc = -ENOMEM);
 
-       snprintf(name, 15, "ptlrpcd_rcv");
+       snprintf(name, sizeof(name), "ptlrpcd_rcv");
        set_bit(LIOD_RECOVERY, &ptlrpcds->pd_thread_rcv.pc_flags);
        rc = ptlrpcd_start(-1, nthreads, name, &ptlrpcds->pd_thread_rcv);
        if (rc < 0)
@@ -764,7 +764,7 @@ static int ptlrpcd_init(void)
         *      unnecessary dependency. But how to distribute async RPCs load
         *      among all the ptlrpc daemons becomes another trouble. */
        for (i = 0; i < nthreads; i++) {
-               snprintf(name, 15, "ptlrpcd_%d", i);
+               snprintf(name, sizeof(name), "ptlrpcd_%d", i);
                rc = ptlrpcd_start(i, nthreads, name, &ptlrpcds->pd_threads[i]);
                if (rc < 0)
                        GOTO(out, rc);
index 9013745ab1059fb716e2f1cb6df2166cd163b4a1..6547f46a7729f2f95c16f9bdff5e334a43806eea 100644 (file)
@@ -59,8 +59,8 @@
  ****************************************/
 
 
-#define PTRS_PER_PAGE   (PAGE_CACHE_SIZE / sizeof(void *))
-#define PAGES_PER_POOL  (PTRS_PER_PAGE)
+#define POINTERS_PER_PAGE      (PAGE_CACHE_SIZE / sizeof(void *))
+#define PAGES_PER_POOL         (POINTERS_PER_PAGE)
 
 #define IDLE_IDX_MAX       (100)
 #define IDLE_IDX_WEIGHT         (3)
@@ -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 ac8b5fd2300b5720e322137079895bdda5f71b52..acf75f3873d1ffb0ab9cc4258150b3a9a1b2e3ba 100644 (file)
@@ -2718,15 +2718,15 @@ int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait)
        spin_unlock(&svcpt->scp_lock);
 
        if (svcpt->scp_cpt >= 0) {
-               snprintf(thread->t_name, PTLRPC_THR_NAME_LEN, "%s%02d_%03d",
+               snprintf(thread->t_name, sizeof(thread->t_name), "%s%02d_%03d",
                         svc->srv_thread_name, svcpt->scp_cpt, thread->t_id);
        } else {
-               snprintf(thread->t_name, PTLRPC_THR_NAME_LEN, "%s_%04d",
+               snprintf(thread->t_name, sizeof(thread->t_name), "%s_%04d",
                         svc->srv_thread_name, thread->t_id);
        }
 
        CDEBUG(D_RPCTRACE, "starting thread '%s'\n", thread->t_name);
-       rc = PTR_ERR(kthread_run(ptlrpc_main, thread, thread->t_name));
+       rc = PTR_ERR(kthread_run(ptlrpc_main, thread, "%s", thread->t_name));
        if (IS_ERR_VALUE(rc)) {
                CERROR("cannot start thread '%s': rc %d\n",
                       thread->t_name, rc);
index d7b3c82b5ead023bcc4ba85acdd0e307b0eecdc9..45dfe94199ae4ecd951a8142fb6f9140d226942c 100644 (file)
@@ -604,7 +604,7 @@ int cvmx_usb_initialize(struct cvmx_usb_state *state, int usb_port_number,
                        }
        }
 
-       memset(usb, 0, sizeof(usb));
+       memset(usb, 0, sizeof(*usb));
        usb->init_flags = flags;
 
        /* Initialize the USB state structure */
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 3605c5da822d953daa6275dda23b675e13b60d5c..6fc77428e83a0c389c51e6cca52ceaa6a8ff7dd9 100644 (file)
@@ -157,8 +157,8 @@ _func_enter_;
 
        *frlen = *frlen + (len + 2);
 
-       return pbuf + len + 2;
 _func_exit_;
+       return pbuf + len + 2;
 }
 
 inline u8 *rtw_set_ie_ch_switch (u8 *buf, u32 *buf_len, u8 ch_switch_mode,
index 8b2ba26ba38d9a44c090167cc9bd862367e92ade..4b2eb8e9b5620ab4529ec9ce8af252ef502a65fc 100644 (file)
@@ -1827,13 +1827,13 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra
 
 #ifdef CONFIG_88EU_P2P
 
-static int get_reg_classes_full_count(struct p2p_channels channel_list)
+static int get_reg_classes_full_count(struct p2p_channels *channel_list)
 {
        int cnt = 0;
        int i;
 
-       for (i = 0; i < channel_list.reg_classes; i++) {
-               cnt += channel_list.reg_class[i].channels;
+       for (i = 0; i < channel_list->reg_classes; i++) {
+               cnt += channel_list->reg_class[i].channels;
        }
 
        return cnt;
@@ -2065,7 +2065,7 @@ void issue_p2p_GO_request(struct adapter *padapter, u8 *raddr)
        /*  + number of channels in all classes */
        len_channellist_attr = 3
           + (1 + 1) * (u16)(pmlmeext->channel_list.reg_classes)
-          + get_reg_classes_full_count(pmlmeext->channel_list);
+          + get_reg_classes_full_count(&pmlmeext->channel_list);
 
        *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
        p2pielen += 2;
@@ -2437,7 +2437,7 @@ static void issue_p2p_GO_response(struct adapter *padapter, u8 *raddr, u8 *frame
        /*  + number of channels in all classes */
        len_channellist_attr = 3
           + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes
-          + get_reg_classes_full_count(pmlmeext->channel_list);
+          + get_reg_classes_full_count(&pmlmeext->channel_list);
 
        *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
 
@@ -2859,7 +2859,7 @@ void issue_p2p_invitation_request(struct adapter *padapter, u8 *raddr)
        /*  + number of channels in all classes */
        len_channellist_attr = 3
           + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes
-          + get_reg_classes_full_count(pmlmeext->channel_list);
+          + get_reg_classes_full_count(&pmlmeext->channel_list);
 
        *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
 
@@ -3120,7 +3120,7 @@ void issue_p2p_invitation_response(struct adapter *padapter, u8 *raddr, u8 dialo
                /*  + number of channels in all classes */
                len_channellist_attr = 3
                        + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes
-                       + get_reg_classes_full_count(pmlmeext->channel_list);
+                       + get_reg_classes_full_count(&pmlmeext->channel_list);
 
                *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
                p2pielen += 2;
index c7ff2e4d1f23fcc4567c747bf97beff945886862..9832dcbbd07fa621467dfc1c216411e627db7e66 100644 (file)
@@ -907,7 +907,7 @@ u32 mp_query_psd(struct adapter *pAdapter, u8 *data)
                sscanf(data, "pts =%d, start =%d, stop =%d", &psd_pts, &psd_start, &psd_stop);
        }
 
-       _rtw_memset(data, '\0', sizeof(data));
+       _rtw_memset(data, '\0', sizeof(*data));
 
        i = psd_start;
        while (i < psd_stop) {
index 013ea487e7acc2e57726b82e6e016d4aebf60b34..8018edd3d42e19fcc0875c7324584d94e6fb02ad 100644 (file)
@@ -631,7 +631,7 @@ void WMMOnAssocRsp(struct adapter *padapter)
        inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3;
 
        if (pregpriv->wifi_spec == 1) {
-               u32     j, tmp, change_inx;
+               u32     j, tmp, change_inx = false;
 
                /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */
                for (i = 0; i < 4; i++) {
index 9c2e7a20c09ea1ced218d303db5e1213837be751..ec0028d4e61a495cf577efe82fd7bffa0455fbbd 100644 (file)
@@ -57,7 +57,7 @@ static void Init_ODM_ComInfo_88E(struct adapter *Adapter)
        u8 cut_ver, fab_ver;
 
        /*  Init Value */
-       _rtw_memset(dm_odm, 0, sizeof(dm_odm));
+       _rtw_memset(dm_odm, 0, sizeof(*dm_odm));
 
        dm_odm->Adapter = Adapter;
 
index 2bfe72841921bd8fc76ec684130f691e5466e50a..4787bacdcad892da62bf66c05cadb851e090e09d 100644 (file)
@@ -1010,7 +1010,7 @@ enum dm_dig_op {
 #define                DM_false_ALARM_THRESH_LOW       400
 #define                DM_false_ALARM_THRESH_HIGH      1000
 
-#define                DM_DIG_MAX_NIC                  0x3e
+#define                DM_DIG_MAX_NIC                  0x4e
 #define                DM_DIG_MIN_NIC                  0x1e /* 0x22/0x1c */
 
 #define                DM_DIG_MAX_AP                   0x32
index 52b280165a926da8acccb981e539c787c6c422b9..555c801d2ded7e434a5a86335449d5be377796ee 100644 (file)
@@ -188,7 +188,7 @@ enum ChannelPlan {
 
 struct txpowerinfo24g {
        u8 IndexCCK_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
-       u8 IndexBW40_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G-1];
+       u8 IndexBW40_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
        /* If only one tx, only BW20 and OFDM are used. */
        s8 CCK_Diff[MAX_RF_PATH][MAX_TX_COUNT];
        s8 OFDM_Diff[MAX_RF_PATH][MAX_TX_COUNT];
index a96b018e5e6a3d7208867684983a58ede36c8e82..853ab80a2b860a0a95bfab8d85ba064ca4eef982 100644 (file)
@@ -870,6 +870,7 @@ static struct fwevent wlanevents[] = {
        {0, NULL},
        {0, NULL},
        {0, &rtw_cpwm_event_callback},
+       {0, NULL},
 };
 
 #endif/* _RTL_MLME_EXT_C_ */
index cd4100fb3645ffd1cc2fcb8ec1013c1fa76d30da..95953ebc027922e66ffd3168a965dee33f6a30be 100644 (file)
@@ -6973,7 +6973,7 @@ static int rtw_mp_ctx(struct net_device *dev,
        stop = strncmp(extra, "stop", 4);
        sscanf(extra, "count =%d, pkt", &count);
 
-       _rtw_memset(extra, '\0', sizeof(extra));
+       _rtw_memset(extra, '\0', sizeof(*extra));
 
        if (stop == 0) {
                bStartTest = 0; /*  To set Stop */
index d3078d200e505f4c4f24237eb202d80ae6e9cd69..9ca3180ebaa0e70fbb188c84748971fd4f34922d 100644 (file)
@@ -54,6 +54,7 @@ static struct usb_device_id rtw_usb_id_tbl[] = {
        /*=== Customer ID ===*/
        /****** 8188EUS ********/
        {USB_DEVICE(0x8179, 0x07B8)}, /* Abocom - Abocom */
+       {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */
        {}      /* Terminating entry */
 };
 
index 5bc361b16d4ca05e924bd3a326824c852a67b8f0..56144014b7c9ba15126f97b073fb6eea4777937a 100644 (file)
@@ -37,6 +37,8 @@ rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
        /* Get TCB and local buffer from common pool.
           (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) */
        skb  = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
+       if (!skb)
+               return RT_STATUS_FAILURE;
        memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
        tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
        tcb_desc->queue_index = TXCMD_QUEUE;
index dbf11ecb794ec60dd576578f9f5172d0f4448f10..19d3cf451b880c736c82cce806fdfb14d98b6379 100644 (file)
@@ -172,8 +172,8 @@ static u16 swGetOFDMControlRate(struct vnt_private *pDevice, u16 wRateIdx)
        if (!CARDbIsOFDMinBasicRate(pDevice)) {
                DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
                        "swGetOFDMControlRate:(NO OFDM) %d\n", wRateIdx);
-       if (wRateIdx > RATE_24M)
-               wRateIdx = RATE_24M;
+               if (wRateIdx > RATE_24M)
+                       wRateIdx = RATE_24M;
                return wRateIdx;
        }
 
index d0cf7d8a20e5640fe507f3ff1b1dc64c170f9408..8872e0f84f40e825efec5dd7f7614f6c22f43562 100644 (file)
@@ -1634,6 +1634,9 @@ int iwctl_siwencodeext(struct net_device *dev, struct iw_request_info *info,
        if (pMgmt == NULL)
                return -EFAULT;
 
+       if (!(pDevice->flags & DEVICE_FLAGS_OPENED))
+               return -ENODEV;
+
        buf = kzalloc(sizeof(struct viawget_wpa_param), GFP_KERNEL);
        if (buf == NULL)
                return -ENOMEM;
index 536971786ae8e4cb87c27b4705d006df0d5cbee6..6f9d28182445ce99b2d37bcd37aaae3c3d2bdc03 100644 (file)
@@ -1098,6 +1098,8 @@ static int device_close(struct net_device *dev)
     memset(pMgmt->abyCurrBSSID, 0, 6);
     pMgmt->eCurrState = WMAC_STATE_IDLE;
 
+       pDevice->flags &= ~DEVICE_FLAGS_OPENED;
+
     device_free_tx_bufs(pDevice);
     device_free_rx_bufs(pDevice);
     device_free_int_bufs(pDevice);
@@ -1109,7 +1111,6 @@ static int device_close(struct net_device *dev)
     usb_free_urb(pDevice->pInterruptURB);
 
     BSSvClearNodeDBTable(pDevice, 0);
-    pDevice->flags &=(~DEVICE_FLAGS_OPENED);
 
     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_close2 \n");
 
index fb743a8811bbc9c0c8c37d23bde37a96b863d735..14f3e852215da5fb27702b4b91687047b9a290c2 100644 (file)
@@ -148,6 +148,8 @@ static void *s_vGetFreeContext(struct vnt_private *pDevice)
     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"GetFreeContext()\n");
 
     for (ii = 0; ii < pDevice->cbTD; ii++) {
+       if (!pDevice->apTD[ii])
+               return NULL;
         pContext = pDevice->apTD[ii];
         if (pContext->bBoolInUse == false) {
             pContext->bBoolInUse = true;
index efc56987a60b53a0a409277da639a95b128f5304..7db6f03a00540cd8c2a131ab7039fec6251b72cc 100644 (file)
@@ -2054,7 +2054,7 @@ static int xillybus_init_chrdev(struct xilly_endpoint *endpoint,
                                       NULL,
                                       MKDEV(major, i),
                                       NULL,
-                                      devname);
+                                      "%s", devname);
 
                if (IS_ERR(device)) {
                        pr_warn("xillybus: Failed to create %s "
index 91d94b564433ad2aa3f8b6b5091ca26d03459477..2c4ed52ca849d45b385cbeed0d88a545d4a5fa5d 100644 (file)
@@ -981,4 +981,3 @@ MODULE_PARM_DESC(num_devices, "Number of zram devices");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
 MODULE_DESCRIPTION("Compressed RAM Block Device");
-MODULE_ALIAS("devname:zram");
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..38e44b9abf0f145eacde1e9b90dcf26c45ca2633 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);
@@ -766,7 +753,8 @@ static void iscsit_unmap_iovec(struct iscsi_cmd *cmd)
 
 static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
 {
-       struct iscsi_cmd *cmd;
+       LIST_HEAD(ack_list);
+       struct iscsi_cmd *cmd, *cmd_p;
 
        conn->exp_statsn = exp_statsn;
 
@@ -774,19 +762,23 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
                return;
 
        spin_lock_bh(&conn->cmd_lock);
-       list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
+       list_for_each_entry_safe(cmd, cmd_p, &conn->conn_cmd_list, i_conn_node) {
                spin_lock(&cmd->istate_lock);
                if ((cmd->i_state == ISTATE_SENT_STATUS) &&
                    iscsi_sna_lt(cmd->stat_sn, exp_statsn)) {
                        cmd->i_state = ISTATE_REMOVE;
                        spin_unlock(&cmd->istate_lock);
-                       iscsit_add_cmd_to_immediate_queue(cmd, conn,
-                                               cmd->i_state);
+                       list_move_tail(&cmd->i_conn_node, &ack_list);
                        continue;
                }
                spin_unlock(&cmd->istate_lock);
        }
        spin_unlock_bh(&conn->cmd_lock);
+
+       list_for_each_entry_safe(cmd, cmd_p, &ack_list, i_conn_node) {
+               list_del(&cmd->i_conn_node);
+               iscsit_free_cmd(cmd, false);
+       }
 }
 
 static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
@@ -3447,12 +3439,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..ef6d836a4d09745d57ba42e2496dd725f85c57ea 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 += (tag_num / 2) + 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..b0cac0c342e1e83a9da5dc7b5f01edd48cb12136 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)
@@ -735,7 +736,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
                 * Fallthrough
                 */
        case ISCSI_OP_SCSI_TMFUNC:
-               rc = transport_generic_free_cmd(&cmd->se_cmd, 1);
+               rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown);
                if (!rc && shutdown && se_cmd && se_cmd->se_sess) {
                        __iscsit_free_cmd(cmd, true, shutdown);
                        target_put_sess_cmd(se_cmd->se_sess, se_cmd);
@@ -751,7 +752,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
                        se_cmd = &cmd->se_cmd;
                        __iscsit_free_cmd(cmd, true, shutdown);
 
-                       rc = transport_generic_free_cmd(&cmd->se_cmd, 1);
+                       rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown);
                        if (!rc && shutdown && se_cmd->se_sess) {
                                __iscsit_free_cmd(cmd, true, shutdown);
                                target_put_sess_cmd(se_cmd->se_sess, se_cmd);
@@ -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..4714c6f8da4be5fe39e797237fa8a35de0450883 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,217 @@ 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;
+
+       /*
+        * Only set SCF_COMPARE_AND_WRITE_POST to force a response fall-through
+        * within target_complete_ok_work() if the command was successfully
+        * sent to the backend driver.
+        */
+       spin_lock_irq(&cmd->t_state_lock);
+       if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status)
+               cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST;
+       spin_unlock_irq(&cmd->t_state_lock);
+
+       /*
+        * 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 = NULL, *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;
+       /*
+        * Immediately exit + release dev->caw_sem if command has already
+        * been failed with a non-zero SCSI status.
+        */
+       if (cmd->scsi_status) {
+               pr_err("compare_and_write_callback: non zero scsi_status:"
+                       " 0x%02x\n", cmd->scsi_status);
+               goto out;
+       }
+
+       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;
+       }
+       /*
+        * Reset cmd->data_length to individual block_size in order to not
+        * confuse backend drivers that depend on this value matching the
+        * size of the I/O being submitted.
+        */
+       cmd->data_length = cmd->t_task_nolb * dev->dev_attrib.block_size;
+
+       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 +562,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 +600,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 +609,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 +618,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 +633,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 +657,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 +685,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 +846,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..81e945eefbbdd0572181d84e3cd9d014895e4eb7 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,57 @@ 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 | __GFP_NOWARN | __GFP_REPEAT);
+       if (!se_sess->sess_cmd_map) {
+               se_sess->sess_cmd_map = vzalloc(tag_num * tag_size);
+               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);
+               if (is_vmalloc_addr(se_sess->sess_cmd_map))
+                       vfree(se_sess->sess_cmd_map);
+               else
+                       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 +417,13 @@ 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);
+               if (is_vmalloc_addr(se_sess->sess_cmd_map))
+                       vfree(se_sess->sess_cmd_map);
+               else
+                       kfree(se_sess->sess_cmd_map);
+       }
        kmem_cache_free(se_sess_cache, se_sess);
 }
 EXPORT_SYMBOL(transport_free_session);
@@ -1206,7 +1263,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 +1569,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 +1643,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 +1848,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 +1920,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 +1964,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 +2009,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 +2127,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 +2150,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 +2184,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 +2857,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..3da4fd1
--- /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] & 0xff) << 16;
+               xop->dbl |= (desc[30] & 0xff) << 8;
+               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 e61c36cbb866474841f9bdf92d934d3c5ece137a..c193af6a628f45758a7fcd59b1b0823e57327655 100644 (file)
@@ -636,6 +636,7 @@ struct console xenboot_console = {
        .name           = "xenboot",
        .write          = xenboot_write_console,
        .flags          = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
+       .index          = -1,
 };
 #endif /* CONFIG_EARLY_PRINTK */
 
index c9a9ddd1d0bc2aa5091d7e1678920df2d9292429..7a744b69c3d144516388d3e8a4bc2fc440fd4d34 100644 (file)
@@ -1758,8 +1758,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
                canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON;
        if (canon_change) {
                bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
-               ldata->line_start = 0;
-               ldata->canon_head = ldata->read_tail;
+               ldata->line_start = ldata->canon_head = ldata->read_tail;
                ldata->erasing = 0;
                ldata->lnext = 0;
        }
@@ -2184,28 +2183,34 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
 
                if (!input_available_p(tty, 0)) {
                        if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-                               retval = -EIO;
-                               break;
-                       }
-                       if (tty_hung_up_p(file))
-                               break;
-                       if (!timeout)
-                               break;
-                       if (file->f_flags & O_NONBLOCK) {
-                               retval = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               retval = -ERESTARTSYS;
-                               break;
-                       }
-                       n_tty_set_room(tty);
-                       up_read(&tty->termios_rwsem);
+                               up_read(&tty->termios_rwsem);
+                               tty_flush_to_ldisc(tty);
+                               down_read(&tty->termios_rwsem);
+                               if (!input_available_p(tty, 0)) {
+                                       retval = -EIO;
+                                       break;
+                               }
+                       } else {
+                               if (tty_hung_up_p(file))
+                                       break;
+                               if (!timeout)
+                                       break;
+                               if (file->f_flags & O_NONBLOCK) {
+                                       retval = -EAGAIN;
+                                       break;
+                               }
+                               if (signal_pending(current)) {
+                                       retval = -ERESTARTSYS;
+                                       break;
+                               }
+                               n_tty_set_room(tty);
+                               up_read(&tty->termios_rwsem);
 
-                       timeout = schedule_timeout(timeout);
+                               timeout = schedule_timeout(timeout);
 
-                       down_read(&tty->termios_rwsem);
-                       continue;
+                               down_read(&tty->termios_rwsem);
+                               continue;
+                       }
                }
                __set_current_state(TASK_RUNNING);
 
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 a0ebbc9ce5cdbacc69cc8c240f8d9fd76e43ec12..042aa077b5b3e166a8453ac0684da1dd024f6785 100644 (file)
@@ -1912,9 +1912,6 @@ static int serial_imx_probe_dt(struct imx_port *sport,
 
        sport->devdata = of_id->data;
 
-       if (of_device_is_stdout_path(np))
-               add_preferred_console(imx_reg.cons->name, sport->port.line, 0);
-
        return 0;
 }
 #else
index 52379e56a31e7abc43a6642a799b1be7744be6c8..44077c0b7670075625650c9d00cc98a63bb90f5c 100644 (file)
@@ -667,30 +667,21 @@ static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
 
 static int dma_push_rx(struct eg20t_port *priv, int size)
 {
-       struct tty_struct *tty;
        int room;
        struct uart_port *port = &priv->port;
        struct tty_port *tport = &port->state->port;
 
-       port = &priv->port;
-       tty = tty_port_tty_get(tport);
-       if (!tty) {
-               dev_dbg(priv->port.dev, "%s:tty is busy now", __func__);
-               return 0;
-       }
-
        room = tty_buffer_request_room(tport, size);
 
        if (room < size)
                dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
                         size - room);
        if (!room)
-               return room;
+               return 0;
 
        tty_insert_flip_string(tport, sg_virt(&priv->sg_rx), size);
 
        port->icount.rx += room;
-       tty_kref_put(tty);
 
        return room;
 }
@@ -1098,6 +1089,8 @@ static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr)
        if (tty == NULL) {
                for (i = 0; error_msg[i] != NULL; i++)
                        dev_err(&priv->pdev->dev, error_msg[i]);
+       } else {
+               tty_kref_put(tty);
        }
 }
 
index d0d972f7e43e3759fb03119786a1103764c86730..0489a2bdcdf9a1aff4af5dacd1d7766f9671a523 100644 (file)
@@ -732,7 +732,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
 static void tegra_uart_stop_rx(struct uart_port *u)
 {
        struct tegra_uart_port *tup = to_tegra_uport(u);
-       struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
+       struct tty_struct *tty;
        struct tty_port *port = &u->state->port;
        struct dma_tx_state state;
        unsigned long ier;
@@ -744,6 +744,8 @@ static void tegra_uart_stop_rx(struct uart_port *u)
        if (!tup->rx_in_progress)
                return;
 
+       tty = tty_port_tty_get(&tup->uport.state->port);
+
        tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */
 
        ier = tup->ier_shadow;
index 93b697a0de658ddc6769fedbe822b1151fef4bab..15ad6fcda88b323b2f5711b753ee76126741ea04 100644 (file)
@@ -561,12 +561,13 @@ static int vt8500_serial_probe(struct platform_device *pdev)
        if (!mmres || !irqres)
                return -ENODEV;
 
-       if (np)
+       if (np) {
                port = of_alias_get_id(np, "serial");
                if (port >= VT8500_MAX_PORTS)
                        port = -1;
-       else
+       } else {
                port = -1;
+       }
 
        if (port < 0) {
                /* calculate the port id */
index d5cc3acecfd382d820b9eb5d5c3fbebf0f105b71..40a9fe9d3b10f0170af31c4d8845d8cc609e6bb5 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/moduleparam.h>
 #include <linux/jiffies.h>
 #include <linux/syscalls.h>
+#include <linux/of.h>
 
 #include <asm/ptrace.h>
 #include <asm/irq_regs.h>
@@ -681,6 +682,40 @@ static void sysrq_detect_reset_sequence(struct sysrq_state *state,
        }
 }
 
+#ifdef CONFIG_OF
+static void sysrq_of_get_keyreset_config(void)
+{
+       u32 key;
+       struct device_node *np;
+       struct property *prop;
+       const __be32 *p;
+
+       np = of_find_node_by_path("/chosen/linux,sysrq-reset-seq");
+       if (!np) {
+               pr_debug("No sysrq node found");
+               return;
+       }
+
+       /* Reset in case a __weak definition was present */
+       sysrq_reset_seq_len = 0;
+
+       of_property_for_each_u32(np, "keyset", prop, p, key) {
+               if (key == KEY_RESERVED || key > KEY_MAX ||
+                   sysrq_reset_seq_len == SYSRQ_KEY_RESET_MAX)
+                       break;
+
+               sysrq_reset_seq[sysrq_reset_seq_len++] = (unsigned short)key;
+       }
+
+       /* Get reset timeout if any. */
+       of_property_read_u32(np, "timeout-ms", &sysrq_reset_downtime_ms);
+}
+#else
+static void sysrq_of_get_keyreset_config(void)
+{
+}
+#endif
+
 static void sysrq_reinject_alt_sysrq(struct work_struct *work)
 {
        struct sysrq_state *sysrq =
@@ -914,6 +949,7 @@ static inline void sysrq_register_handler(void)
        int error;
        int i;
 
+       /* First check if a __weak interface was instantiated. */
        for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
                key = platform_sysrq_reset_seq[i];
                if (key == KEY_RESERVED || key > KEY_MAX)
@@ -922,6 +958,12 @@ static inline void sysrq_register_handler(void)
                sysrq_reset_seq[sysrq_reset_seq_len++] = key;
        }
 
+       /*
+        * DT configuration takes precedence over anything that would
+        * have been defined via the __weak interface.
+        */
+       sysrq_of_get_keyreset_config();
+
        error = input_register_handler(&sysrq_handler);
        if (error)
                pr_err("Failed to register input handler, error %d", error);
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 03ba081c577251a0947466b79f23b36b359b51c1..6fd60fece6b4b01684695b7df4af376e695ff873 100644 (file)
@@ -1201,6 +1201,9 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
                }
                return 0;
        case TCFLSH:
+               retval = tty_check_change(tty);
+               if (retval)
+                       return retval;
                return __tty_perform_flush(tty, arg);
        default:
                /* Try the mode commands */
index 4a851e15e58cdfb6832fbc14c93e3e96cb6f9515..77b47d82c9a69d05d7985068fb956f961b6481f1 100644 (file)
@@ -1,6 +1,6 @@
 config USB_CHIPIDEA
        tristate "ChipIdea Highspeed Dual Role Controller"
-       depends on (USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)
+       depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA
        help
          Say Y here if your system has a dual role high speed USB
          controller based on ChipIdea silicon IP. Currently, only the
index 74d998d9b45b28001e2f15f6026640ecb6e07085..be822a2c1776cc30c2df5f3ed7840aff68ef10ac 100644 (file)
@@ -131,7 +131,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
                if (ret) {
                        dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n",
                                        ret);
-                       goto err_clk;
+                       goto err_phy;
                }
        }
 
@@ -143,7 +143,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
                dev_err(&pdev->dev,
                        "Can't register ci_hdrc platform device, err=%d\n",
                        ret);
-               goto err_clk;
+               goto err_phy;
        }
 
        if (data->usbmisc_data) {
@@ -164,6 +164,9 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
 
 disable_device:
        ci_hdrc_remove_device(data->ci_pdev);
+err_phy:
+       if (data->phy)
+               usb_phy_shutdown(data->phy);
 err_clk:
        clk_disable_unprepare(data->clk);
        return ret;
index 042320a6c6c79278ac27191980c0fb63f7ddfc35..d514332ac0811c9fec55a40253b3c526d19cde6d 100644 (file)
@@ -129,7 +129,12 @@ static DEFINE_PCI_DEVICE_TABLE(ci_hdrc_pci_id_table) = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),
                .driver_data = (kernel_ulong_t)&penwell_pci_platdata,
        },
-       { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
+       {
+               /* Intel Clovertrail */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe006),
+               .driver_data = (kernel_ulong_t)&penwell_pci_platdata,
+       },
+       { 0 } /* end: all zeroes */
 };
 MODULE_DEVICE_TABLE(pci, ci_hdrc_pci_id_table);
 
index 94626409559a96a79c0d027023dbade8a645ce58..23763dcec069b2e8d1ba6dd140fc9cf644d2ddec 100644 (file)
@@ -605,6 +605,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
        dbg_remove_files(ci);
        free_irq(ci->irq, ci);
        ci_role_destroy(ci);
+       kfree(ci->hw_bank.regmap);
 
        return 0;
 }
index 6f96795dd20cc3ff3d0c08490ae8d87b0b2ccccf..64d7a6d9a1adcbd679258661a6b5875bd8bf834a 100644 (file)
@@ -100,8 +100,10 @@ static void host_stop(struct ci_hdrc *ci)
 {
        struct usb_hcd *hcd = ci->hcd;
 
-       usb_remove_hcd(hcd);
-       usb_put_hcd(hcd);
+       if (hcd) {
+               usb_remove_hcd(hcd);
+               usb_put_hcd(hcd);
+       }
        if (ci->platdata->reg_vbus)
                regulator_disable(ci->platdata->reg_vbus);
 }
index 6b4c2f2eb94649c7da6fc577b54598d53ebdfec4..9333083dd1111c047c7016a44402242e2aa87f7d 100644 (file)
@@ -1600,6 +1600,8 @@ static void destroy_eps(struct ci_hdrc *ci)
        for (i = 0; i < ci->hw_ep_max; i++) {
                struct ci_hw_ep *hwep = &ci->ci_hw_ep[i];
 
+               if (hwep->pending_td)
+                       free_pending_td(hwep);
                dma_pool_free(ci->qh_pool, hwep->qh.ptr, hwep->qh.dma);
        }
 }
@@ -1667,13 +1669,13 @@ static int ci_udc_stop(struct usb_gadget *gadget,
                if (ci->platdata->notify_event)
                        ci->platdata->notify_event(ci,
                        CI_HDRC_CONTROLLER_STOPPED_EVENT);
-               ci->driver = NULL;
                spin_unlock_irqrestore(&ci->lock, flags);
                _gadget_stop_activity(&ci->gadget);
                spin_lock_irqsave(&ci->lock, flags);
                pm_runtime_put(&ci->gadget.dev);
        }
 
+       ci->driver = NULL;
        spin_unlock_irqrestore(&ci->lock, flags);
 
        return 0;
index 737e3c19967bee3e81f57cc041ec9989ec38fb57..71dc5d768fa5cef3edc5ac27c84c032d2a0a0dcf 100644 (file)
@@ -742,6 +742,22 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
                if ((index & ~USB_DIR_IN) == 0)
                        return 0;
                ret = findintfep(ps->dev, index);
+               if (ret < 0) {
+                       /*
+                        * Some not fully compliant Win apps seem to get
+                        * index wrong and have the endpoint number here
+                        * rather than the endpoint address (with the
+                        * correct direction). Win does let this through,
+                        * so we'll not reject it here but leave it to
+                        * the device to not break KVM. But we warn.
+                        */
+                       ret = findintfep(ps->dev, index ^ 0x80);
+                       if (ret >= 0)
+                               dev_info(&ps->dev->dev,
+                                       "%s: process %i (%s) requesting ep %02x but needs %02x\n",
+                                       __func__, task_pid_nr(current),
+                                       current->comm, index, index ^ 0x80);
+               }
                if (ret >= 0)
                        ret = checkintf(ps, ret);
                break;
index dde4c83516a1870bd4ed7a11e3fe433ced0979af..e6b682c6c236b8152561496b2e00bba22e75e25c 100644 (file)
@@ -3426,6 +3426,9 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
        unsigned long long u2_pel;
        int ret;
 
+       if (udev->state != USB_STATE_CONFIGURED)
+               return 0;
+
        /* Convert SEL and PEL stored in ns to us */
        u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
        u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
index 5b44cd47da5b28b30046bead355aa54eda3eec0f..01fe36273f3b144cb1c1fe3306ebdf16459c605f 100644 (file)
@@ -97,6 +97,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Alcor Micro Corp. Hub */
        { USB_DEVICE(0x058f, 0x9254), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* MicroTouch Systems touchscreen */
+       { USB_DEVICE(0x0596, 0x051e), .driver_info = USB_QUIRK_RESET_RESUME },
+
        /* appletouch */
        { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME },
 
@@ -130,6 +133,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Broadcom BCM92035DGROM BT dongle */
        { USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* MAYA44USB sound device */
+       { USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME },
+
        /* Action Semiconductor flash disk */
        { USB_DEVICE(0x10d6, 0x2200), .driver_info =
                        USB_QUIRK_STRING_FETCH_255 },
index f969ea266acb854850d151c06294f29c330ca793..70fc43027a5c65b6f29f22dc9ec64c18db220323 100644 (file)
@@ -1,7 +1,6 @@
 config USB_DWC3
        tristate "DesignWare USB3 DRD Core Support"
-       depends on (USB || USB_GADGET) && GENERIC_HARDIRQS && HAS_DMA
-       depends on EXTCON
+       depends on (USB || USB_GADGET) && HAS_DMA
        select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
        help
          Say Y or M here if your system has a Dual Role SuperSpeed
index 9b138129e856aa22b27c4a83398adf55c8949247..2e252aae51ca0bcc5da41b3251c45cec91cced7d 100644 (file)
@@ -28,6 +28,8 @@
 /* FIXME define these in <linux/pci_ids.h> */
 #define PCI_VENDOR_ID_SYNOPSYS         0x16c3
 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3        0xabcd
+#define PCI_DEVICE_ID_INTEL_BYT                0x0f37
+#define PCI_DEVICE_ID_INTEL_MRFLD      0x119e
 
 struct dwc3_pci {
        struct device           *dev;
@@ -187,6 +189,8 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
                PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
                                PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
        },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
        {  }    /* Terminating Entry */
 };
 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
index f168eaebdef8fc6731de7c6994c658737495fdce..5452c0fce36074d4238e3553bb00d879d8df9ac3 100644 (file)
@@ -2611,15 +2611,13 @@ int dwc3_gadget_init(struct dwc3 *dwc)
        ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
        if (ret) {
                dev_err(dwc->dev, "failed to register udc\n");
-               goto err5;
+               goto err4;
        }
 
        return 0;
 
-err5:
-       dwc3_gadget_free_endpoints(dwc);
-
 err4:
+       dwc3_gadget_free_endpoints(dwc);
        dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
                        dwc->ep0_bounce, dwc->ep0_bounce_addr);
 
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 5a5acf22c694514f5b3ebede7903f9912e4138b5..e126b6b248e63cd1b412bea2561e90bd15a104d3 100644 (file)
@@ -113,12 +113,6 @@ static int __init cdc_do_config(struct usb_configuration *c)
                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       fi_ecm = usb_get_function_instance("ecm");
-       if (IS_ERR(fi_ecm)) {
-               status = PTR_ERR(fi_ecm);
-               goto err_func_ecm;
-       }
-
        f_ecm = usb_get_function(fi_ecm);
        if (IS_ERR(f_ecm)) {
                status = PTR_ERR(f_ecm);
@@ -129,35 +123,24 @@ static int __init cdc_do_config(struct usb_configuration *c)
        if (status)
                goto err_add_ecm;
 
-       fi_serial = usb_get_function_instance("acm");
-       if (IS_ERR(fi_serial)) {
-               status = PTR_ERR(fi_serial);
-               goto err_get_acm;
-       }
-
        f_acm = usb_get_function(fi_serial);
        if (IS_ERR(f_acm)) {
                status = PTR_ERR(f_acm);
-               goto err_func_acm;
+               goto err_get_acm;
        }
 
        status = usb_add_function(c, f_acm);
        if (status)
                goto err_add_acm;
-
        return 0;
 
 err_add_acm:
        usb_put_function(f_acm);
-err_func_acm:
-       usb_put_function_instance(fi_serial);
 err_get_acm:
        usb_remove_function(c, f_ecm);
 err_add_ecm:
        usb_put_function(f_ecm);
 err_get_ecm:
-       usb_put_function_instance(fi_ecm);
-err_func_ecm:
        return status;
 }
 
index 06ecd08fd57a3174022a3579f458c84f30440123..b8a2376971a47aa357794117f74390aaee01a594 100644 (file)
@@ -923,8 +923,9 @@ static int dummy_udc_stop(struct usb_gadget *g,
        struct dummy_hcd        *dum_hcd = gadget_to_dummy_hcd(g);
        struct dummy            *dum = dum_hcd->dum;
 
-       dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
-                       driver->driver.name);
+       if (driver)
+               dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
+                               driver->driver.name);
 
        dum->driver = NULL;
 
@@ -1000,8 +1001,8 @@ static int dummy_udc_remove(struct platform_device *pdev)
 {
        struct dummy    *dum = platform_get_drvdata(pdev);
 
-       usb_del_gadget_udc(&dum->gadget);
        device_remove_file(&dum->gadget.dev, &dev_attr_function);
+       usb_del_gadget_udc(&dum->gadget);
        return 0;
 }
 
index edab45da37417e16960b75033a46a8453475b77b..8d9e6f7e8f1a5a6c36965dfdd4c5a213f4f917aa 100644 (file)
@@ -995,7 +995,7 @@ static void ecm_unbind(struct usb_configuration *c, struct usb_function *f)
        usb_ep_free_request(ecm->notify, ecm->notify_req);
 }
 
-struct usb_function *ecm_alloc(struct usb_function_instance *fi)
+static struct usb_function *ecm_alloc(struct usb_function_instance *fi)
 {
        struct f_ecm    *ecm;
        struct f_ecm_opts *opts;
index d00392d879db3aa3e75d093d4e26041fa42bcb54..d61c11d765d0a92b9e9e79270e9de4b3cb474ca3 100644 (file)
@@ -624,7 +624,7 @@ static void eem_unbind(struct usb_configuration *c, struct usb_function *f)
        usb_free_all_descriptors(f);
 }
 
-struct usb_function *eem_alloc(struct usb_function_instance *fi)
+static struct usb_function *eem_alloc(struct usb_function_instance *fi)
 {
        struct f_eem    *eem;
        struct f_eem_opts *opts;
index 1a66c5baa0d1f292188a1756cf17d5243b2ffe58..44cf775a86271ccd95cdf9577c283fc899e70d6c 100644 (file)
@@ -1034,37 +1034,19 @@ struct ffs_sb_fill_data {
        struct ffs_file_perms perms;
        umode_t root_mode;
        const char *dev_name;
-       union {
-               /* set by ffs_fs_mount(), read by ffs_sb_fill() */
-               void *private_data;
-               /* set by ffs_sb_fill(), read by ffs_fs_mount */
-               struct ffs_data *ffs_data;
-       };
+       struct ffs_data *ffs_data;
 };
 
 static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
 {
        struct ffs_sb_fill_data *data = _data;
        struct inode    *inode;
-       struct ffs_data *ffs;
+       struct ffs_data *ffs = data->ffs_data;
 
        ENTER();
 
-       /* Initialise data */
-       ffs = ffs_data_new();
-       if (unlikely(!ffs))
-               goto Enomem;
-
        ffs->sb              = sb;
-       ffs->dev_name        = kstrdup(data->dev_name, GFP_KERNEL);
-       if (unlikely(!ffs->dev_name))
-               goto Enomem;
-       ffs->file_perms      = data->perms;
-       ffs->private_data    = data->private_data;
-
-       /* used by the caller of this function */
-       data->ffs_data       = ffs;
-
+       data->ffs_data       = NULL;
        sb->s_fs_info        = ffs;
        sb->s_blocksize      = PAGE_CACHE_SIZE;
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -1080,17 +1062,14 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
                                  &data->perms);
        sb->s_root = d_make_root(inode);
        if (unlikely(!sb->s_root))
-               goto Enomem;
+               return -ENOMEM;
 
        /* EP0 file */
        if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
                                         &ffs_ep0_operations, NULL)))
-               goto Enomem;
+               return -ENOMEM;
 
        return 0;
-
-Enomem:
-       return -ENOMEM;
 }
 
 static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
@@ -1193,6 +1172,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
        struct dentry *rv;
        int ret;
        void *ffs_dev;
+       struct ffs_data *ffs;
 
        ENTER();
 
@@ -1200,18 +1180,30 @@ ffs_fs_mount(struct file_system_type *t, int flags,
        if (unlikely(ret < 0))
                return ERR_PTR(ret);
 
+       ffs = ffs_data_new();
+       if (unlikely(!ffs))
+               return ERR_PTR(-ENOMEM);
+       ffs->file_perms = data.perms;
+
+       ffs->dev_name = kstrdup(dev_name, GFP_KERNEL);
+       if (unlikely(!ffs->dev_name)) {
+               ffs_data_put(ffs);
+               return ERR_PTR(-ENOMEM);
+       }
+
        ffs_dev = functionfs_acquire_dev_callback(dev_name);
-       if (IS_ERR(ffs_dev))
-               return ffs_dev;
+       if (IS_ERR(ffs_dev)) {
+               ffs_data_put(ffs);
+               return ERR_CAST(ffs_dev);
+       }
+       ffs->private_data = ffs_dev;
+       data.ffs_data = ffs;
 
-       data.dev_name = dev_name;
-       data.private_data = ffs_dev;
        rv = mount_nodev(t, flags, &data, ffs_sb_fill);
-
-       /* data.ffs_data is set by ffs_sb_fill */
-       if (IS_ERR(rv))
+       if (IS_ERR(rv) && data.ffs_data) {
                functionfs_release_dev_callback(data.ffs_data);
-
+               ffs_data_put(data.ffs_data);
+       }
        return rv;
 }
 
@@ -2264,6 +2256,8 @@ static int ffs_func_bind(struct usb_configuration *c,
                                   data->raw_descs + ret,
                                   (sizeof data->raw_descs) - ret,
                                   __ffs_func_bind_do_descs, func);
+               if (unlikely(ret < 0))
+                       goto error;
        }
 
        /*
index 313b835eedfd58948d23a96a85ade673347e8114..a01d7d38c01685135a503885342be7f9ec63ebbd 100644 (file)
@@ -2260,10 +2260,12 @@ reset:
                /* Disable the endpoints */
                if (fsg->bulk_in_enabled) {
                        usb_ep_disable(fsg->bulk_in);
+                       fsg->bulk_in->driver_data = NULL;
                        fsg->bulk_in_enabled = 0;
                }
                if (fsg->bulk_out_enabled) {
                        usb_ep_disable(fsg->bulk_out);
+                       fsg->bulk_out->driver_data = NULL;
                        fsg->bulk_out_enabled = 0;
                }
 
index 32db2eee2d8738fe5388f8c00bd2c644ac2b5b20..bbbfd19487784c6ebbfb107a24a7233c45740a45 100644 (file)
@@ -1214,6 +1214,6 @@ static struct platform_driver fotg210_driver = {
 
 module_platform_driver(fotg210_driver);
 
-MODULE_AUTHOR("Yuan-Hsin Chen <yhchen@faraday-tech.com>");
+MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION(DRIVER_DESC);
index f1dd6daabe217c0742140c1619c3be5aa22c8c54..b278abe524539640f14a29f70a1f3a9d25fa1747 100644 (file)
@@ -22,7 +22,7 @@
 
 MODULE_DESCRIPTION("FUSB300  USB gadget driver");
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Yuan Hsin Chen <yhchen@faraday-tech.com>");
+MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>");
 MODULE_ALIAS("platform:fusb300_udc");
 
 #define DRIVER_VERSION "20 October 2010"
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 2a1ebefd8f9eb31318fc861fbc010214148db18d..23393254a8a35593526062cc09880f50c809dced 100644 (file)
@@ -179,7 +179,7 @@ err_conf:
        return ret;
 }
 
-static int rndis_config_register(struct usb_composite_dev *cdev)
+static __ref int rndis_config_register(struct usb_composite_dev *cdev)
 {
        static struct usb_configuration config = {
                .bConfigurationValue    = MULTI_RNDIS_CONFIG_NUM,
@@ -194,7 +194,7 @@ static int rndis_config_register(struct usb_composite_dev *cdev)
 
 #else
 
-static int rndis_config_register(struct usb_composite_dev *cdev)
+static __ref int rndis_config_register(struct usb_composite_dev *cdev)
 {
        return 0;
 }
@@ -241,7 +241,7 @@ err_conf:
        return ret;
 }
 
-static int cdc_config_register(struct usb_composite_dev *cdev)
+static __ref int cdc_config_register(struct usb_composite_dev *cdev)
 {
        static struct usb_configuration config = {
                .bConfigurationValue    = MULTI_CDC_CONFIG_NUM,
@@ -256,7 +256,7 @@ static int cdc_config_register(struct usb_composite_dev *cdev)
 
 #else
 
-static int cdc_config_register(struct usb_composite_dev *cdev)
+static __ref int cdc_config_register(struct usb_composite_dev *cdev)
 {
        return 0;
 }
index bbb6e98c4384292d3446b62f8671decaf0a51c55..561b30efb8ee84de6fc37c33005cdadc6fbcc5ff 100644 (file)
@@ -645,6 +645,7 @@ static int  mv_u3d_ep_disable(struct usb_ep *_ep)
        struct mv_u3d_ep *ep;
        struct mv_u3d_ep_context *ep_context;
        u32 epxcr, direction;
+       unsigned long flags;
 
        if (!_ep)
                return -EINVAL;
@@ -661,7 +662,9 @@ static int  mv_u3d_ep_disable(struct usb_ep *_ep)
        direction = mv_u3d_ep_dir(ep);
 
        /* nuke all pending requests (does flush) */
+       spin_lock_irqsave(&u3d->lock, flags);
        mv_u3d_nuke(ep, -ESHUTDOWN);
+       spin_unlock_irqrestore(&u3d->lock, flags);
 
        /* Disable the endpoint for Rx or Tx and reset the endpoint type */
        if (direction == MV_U3D_EP_DIR_OUT) {
index cc9207473dbc33f204bbd4009eb9e2138f966da6..0ac6064aa3b86b6cd2376324ac9996f8ece1c0a0 100644 (file)
@@ -2054,7 +2054,7 @@ static struct pxa25x_udc memory = {
 /*
  *     probe - binds to the platform device
  */
-static int __init pxa25x_udc_probe(struct platform_device *pdev)
+static int pxa25x_udc_probe(struct platform_device *pdev)
 {
        struct pxa25x_udc *dev = &memory;
        int retval, irq;
@@ -2203,7 +2203,7 @@ static void pxa25x_udc_shutdown(struct platform_device *_dev)
        pullup_off();
 }
 
-static int __exit pxa25x_udc_remove(struct platform_device *pdev)
+static int pxa25x_udc_remove(struct platform_device *pdev)
 {
        struct pxa25x_udc *dev = platform_get_drvdata(pdev);
 
@@ -2294,7 +2294,8 @@ static int pxa25x_udc_resume(struct platform_device *dev)
 
 static struct platform_driver udc_driver = {
        .shutdown       = pxa25x_udc_shutdown,
-       .remove         = __exit_p(pxa25x_udc_remove),
+       .probe          = pxa25x_udc_probe,
+       .remove         = pxa25x_udc_remove,
        .suspend        = pxa25x_udc_suspend,
        .resume         = pxa25x_udc_resume,
        .driver         = {
@@ -2303,7 +2304,7 @@ static struct platform_driver udc_driver = {
        },
 };
 
-module_platform_driver_probe(udc_driver, pxa25x_udc_probe);
+module_platform_driver(udc_driver);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell");
index d69b36a99dbcd8ae5a1bc57275398be86a2562ca..a8a99e4748d522bded4aef1882a7beaafe45603b 100644 (file)
@@ -543,7 +543,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
         * FIFO, requests of >512 cause the endpoint to get stuck with a
         * fragment of the end of the transfer in it.
         */
-       if (can_write > 512)
+       if (can_write > 512 && !periodic)
                can_write = 512;
 
        /*
@@ -2475,8 +2475,6 @@ irq_retry:
        if (gintsts & GINTSTS_ErlySusp) {
                dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n");
                writel(GINTSTS_ErlySusp, hsotg->regs + GINTSTS);
-
-               s3c_hsotg_disconnect(hsotg);
        }
 
        /*
@@ -2962,9 +2960,6 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
        if (!hsotg)
                return -ENODEV;
 
-       if (!driver || driver != hsotg->driver || !driver->unbind)
-               return -EINVAL;
-
        /* all endpoints should be shutdown */
        for (ep = 0; ep < hsotg->num_of_eps; ep++)
                s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
@@ -2972,15 +2967,15 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
        spin_lock_irqsave(&hsotg->lock, flags);
 
        s3c_hsotg_phy_disable(hsotg);
-       regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
 
-       hsotg->driver = NULL;
+       if (!driver)
+               hsotg->driver = NULL;
+
        hsotg->gadget.speed = USB_SPEED_UNKNOWN;
 
        spin_unlock_irqrestore(&hsotg->lock, flags);
 
-       dev_info(hsotg->dev, "unregistered gadget driver '%s'\n",
-                driver->driver.name);
+       regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
 
        return 0;
 }
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 947b009009f111ba710954ea639962b4d4008463..f2407b2e8a996210aec7f3e7a442119fd6928924 100644 (file)
@@ -130,7 +130,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
        }
 
        /* Enable USB controller, 83xx or 8536 */
-       if (pdata->have_sysif_regs)
+       if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6)
                setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);
 
        /* Don't need to set host mode here. It will be done by tdi_reset() */
@@ -232,15 +232,9 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
        case FSL_USB2_PHY_ULPI:
                if (pdata->have_sysif_regs && pdata->controller_ver) {
                        /* controller version 1.6 or above */
+                       clrbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN);
                        setbits32(non_ehci + FSL_SOC_USB_CTRL,
-                                       ULPI_PHY_CLK_SEL);
-                       /*
-                        * Due to controller issue of PHY_CLK_VALID in ULPI
-                        * mode, we set USB_CTRL_USB_EN before checking
-                        * PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work.
-                        */
-                       clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL,
-                                       UTMI_PHY_EN, USB_CTRL_USB_EN);
+                               ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN);
                }
                portsc |= PORT_PTS_ULPI;
                break;
@@ -270,8 +264,9 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
        if (pdata->have_sysif_regs && pdata->controller_ver &&
            (phy_mode == FSL_USB2_PHY_ULPI)) {
                /* check PHY_CLK_VALID to get phy clk valid */
-               if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) &
-                               PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) {
+               if (!(spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) &
+                               PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0) ||
+                               in_be32(non_ehci + FSL_SOC_USB_PRICTRL))) {
                        printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n");
                        return -EINVAL;
                }
@@ -669,7 +664,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
         * generic hardware linkage
         */
        .irq = ehci_irq,
-       .flags = HCD_USB2 | HCD_MEMORY | HCD_BH,
+       .flags = HCD_USB2 | HCD_MEMORY,
 
        /*
         * basic lifecycle operations
index b52a66ce92e8592b123239aa24b724dddfd085fa..83ab51af250f158e735373760f8c008ce6fe0ad8 100644 (file)
@@ -43,7 +43,7 @@ static const struct hc_driver ehci_grlib_hc_driver = {
         * generic hardware linkage
         */
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
+       .flags                  = HCD_MEMORY | HCD_USB2,
 
        /*
         * basic lifecycle operations
index 5d6022f30ebe94b2228c6b38851217af1ee8f477..86ab9fd9fe9e938fc29cadeac72a935e8c26b8ff 100644 (file)
@@ -1158,7 +1158,7 @@ static const struct hc_driver ehci_hc_driver = {
         * generic hardware linkage
         */
        .irq =                  ehci_irq,
-       .flags =                HCD_MEMORY | HCD_USB2 | HCD_BH,
+       .flags =                HCD_MEMORY | HCD_USB2,
 
        /*
         * basic lifecycle operations
index 417c10da945078e37ddf20e7be290e996936074e..35cdbd88bbbef62a93a3aa869c12dbfda8183bf2 100644 (file)
@@ -96,7 +96,7 @@ static const struct hc_driver mv_ehci_hc_driver = {
         * generic hardware linkage
         */
        .irq = ehci_irq,
-       .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
+       .flags = HCD_MEMORY | HCD_USB2,
 
        /*
         * basic lifecycle operations
index ab0397e4d8f3eadae916d07434f4431f3d59def3..45cc00158412ac8a380cda88a28a4bb7536d62fa 100644 (file)
@@ -51,7 +51,7 @@ static const struct hc_driver ehci_octeon_hc_driver = {
         * generic hardware linkage
         */
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
+       .flags                  = HCD_MEMORY | HCD_USB2,
 
        /*
         * basic lifecycle operations
index 6bd299e61f58d23202183f3186c9542f99e93a23..854c2ec7b699d4effe2c9ca6ae4ab264e1a73cd8 100644 (file)
@@ -361,7 +361,7 @@ static struct pci_driver ehci_pci_driver = {
        .remove =       usb_hcd_pci_remove,
        .shutdown =     usb_hcd_pci_shutdown,
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
        .driver =       {
                .pm =   &usb_hcd_pci_pm_ops
        },
index 893b707f0000abf0e323f39b28b6060a3293bcef..601e208bd782c07e9d0bb1b60d238ccbb7774758 100644 (file)
@@ -286,7 +286,7 @@ static const struct hc_driver ehci_msp_hc_driver = {
 #else
        .irq =                  ehci_irq,
 #endif
-       .flags =                HCD_MEMORY | HCD_USB2 | HCD_BH,
+       .flags =                HCD_MEMORY | HCD_USB2,
 
        /*
         * basic lifecycle operations
index 6cc5567bf9c87faaa8c4a21dcb4202e8e6e7fb94..932293fa32de657de2e36ba091127e50009a6ff7 100644 (file)
@@ -28,7 +28,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
         * generic hardware linkage
         */
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
+       .flags                  = HCD_MEMORY | HCD_USB2,
 
        /*
         * basic lifecycle operations
index 8188542ba17ea01214a3ab0f269fe07cb6cb1744..fd983771b02559cb56c6210e6813d9b223a80f7a 100644 (file)
@@ -71,7 +71,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
        .product_desc           = "PS3 EHCI Host Controller",
        .hcd_priv_size          = sizeof(struct ehci_hcd),
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
+       .flags                  = HCD_MEMORY | HCD_USB2,
        .reset                  = ps3_ehci_hc_reset,
        .start                  = ehci_run,
        .stop                   = ehci_stop,
index e321804c34755553afcf3c1ceab38678ed27af1b..a7f776a13eb17133459f23ac584b60287e544197 100644 (file)
@@ -247,6 +247,8 @@ static int qtd_copy_status (
 
 static void
 ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
+__releases(ehci->lock)
+__acquires(ehci->lock)
 {
        if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
                /* ... update hc-wide periodic stats */
@@ -272,8 +274,11 @@ ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
                urb->actual_length, urb->transfer_buffer_length);
 #endif
 
+       /* complete() can reenter this HCD */
        usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+       spin_unlock (&ehci->lock);
        usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
+       spin_lock (&ehci->lock);
 }
 
 static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
index 8a734498079bc176938c57a6b132c146e9be00dd..b2de52d3961488f249aeb9d4026efe2d603b72bb 100644 (file)
@@ -55,7 +55,7 @@ const struct hc_driver ehci_sead3_hc_driver = {
         * generic hardware linkage
         */
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
+       .flags                  = HCD_MEMORY | HCD_USB2,
 
        /*
         * basic lifecycle operations
index dc899eb2b86183561351d78e8dba1ceffc9cbb18..93e59a13bc1fec919ef81690bbce9f4bdcd3e951 100644 (file)
@@ -36,7 +36,7 @@ static const struct hc_driver ehci_sh_hc_driver = {
         * generic hardware linkage
         */
        .irq                            = ehci_irq,
-       .flags                          = HCD_USB2 | HCD_MEMORY | HCD_BH,
+       .flags                          = HCD_USB2 | HCD_MEMORY,
 
        /*
         * basic lifecycle operations
index 67026ffbf9a871c9780a4b0b7f0d6c739c904e73..cca4be90a864dba009c852f606653fb5fe60d568 100644 (file)
@@ -61,7 +61,7 @@ static const struct hc_driver ehci_tilegx_hc_driver = {
         * Generic hardware linkage.
         */
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
+       .flags                  = HCD_MEMORY | HCD_USB2,
 
        /*
         * Basic lifecycle operations.
index 1c370dfbee0d35e6a3cf2b1288836df2116599c5..59e0e24c753febfb76369be8f872cb3731c2f365 100644 (file)
@@ -108,7 +108,7 @@ static const struct hc_driver ehci_w90x900_hc_driver = {
         * generic hardware linkage
         */
        .irq = ehci_irq,
-       .flags = HCD_USB2|HCD_MEMORY|HCD_BH,
+       .flags = HCD_USB2|HCD_MEMORY,
 
        /*
         * basic lifecycle operations
index 95979f9f4381d8e8e573c7e0fe254d5585d23ab8..eba962e6ebfbbd8ffdd46a85e0fed5ec9b18b78a 100644 (file)
@@ -79,7 +79,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = {
         * generic hardware linkage
         */
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
+       .flags                  = HCD_MEMORY | HCD_USB2,
 
        /*
         * basic lifecycle operations
index 9e0020d9e4c8cc01353ef4b804a9ba9d50bc8cfd..abd5050a4899bdb4518294175477a418583c4e83 100644 (file)
@@ -24,7 +24,7 @@ struct fsl_usb2_dev_data {
        enum fsl_usb2_operating_modes op_mode;  /* operating mode */
 };
 
-struct fsl_usb2_dev_data dr_mode_data[] = {
+static struct fsl_usb2_dev_data dr_mode_data[] = {
        {
                .dr_mode = "host",
                .drivers = { "fsl-ehci", NULL, NULL, },
@@ -42,7 +42,7 @@ struct fsl_usb2_dev_data dr_mode_data[] = {
        },
 };
 
-struct fsl_usb2_dev_data *get_dr_mode_data(struct device_node *np)
+static struct fsl_usb2_dev_data *get_dr_mode_data(struct device_node *np)
 {
        const unsigned char *prop;
        int i;
@@ -75,7 +75,7 @@ static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
        return FSL_USB2_PHY_NONE;
 }
 
-struct platform_device *fsl_usb2_device_register(
+static struct platform_device *fsl_usb2_device_register(
                                        struct platform_device *ofdev,
                                        struct fsl_usb2_platform_data *pdata,
                                        const char *name, int id)
index 60a5de505ca1845609fe34278405e752ddf73226..adb01d950a165f7cf7d5e1a54fe6b674b4cb533a 100644 (file)
@@ -824,13 +824,13 @@ static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd,
                        i = DIV_ROUND_UP(wrap_frame(
                                        cur_frame - urb->start_frame),
                                        urb->interval);
-                       if (urb->transfer_flags & URB_ISO_ASAP) {
+
+                       /* Treat underruns as if URB_ISO_ASAP was set */
+                       if ((urb->transfer_flags & URB_ISO_ASAP) ||
+                                       i >= urb->number_of_packets) {
                                urb->start_frame = wrap_frame(urb->start_frame
                                                + i * urb->interval);
                                i = 0;
-                       } else if (i >= urb->number_of_packets) {
-                               ret = -EXDEV;
-                               goto alloc_dmem_failed;
                        }
                }
        }
index 8f6b695af6a470c5f5d5a5ca6a278e3a1186dfcc..604cad1bcf9cd984666aaf0b2b797b48ee6e3382 100644 (file)
@@ -216,31 +216,26 @@ static int ohci_urb_enqueue (
                        frame &= ~(ed->interval - 1);
                        frame |= ed->branch;
                        urb->start_frame = frame;
+                       ed->last_iso = frame + ed->interval * (size - 1);
                }
        } else if (ed->type == PIPE_ISOCHRONOUS) {
                u16     next = ohci_frame_no(ohci) + 1;
                u16     frame = ed->last_iso + ed->interval;
+               u16     length = ed->interval * (size - 1);
 
                /* Behind the scheduling threshold? */
                if (unlikely(tick_before(frame, next))) {
 
-                       /* USB_ISO_ASAP: Round up to the first available slot */
+                       /* URB_ISO_ASAP: Round up to the first available slot */
                        if (urb->transfer_flags & URB_ISO_ASAP) {
                                frame += (next - frame + ed->interval - 1) &
                                                -ed->interval;
 
                        /*
-                        * Not ASAP: Use the next slot in the stream.  If
-                        * the entire URB falls before the threshold, fail.
+                        * Not ASAP: Use the next slot in the stream,
+                        * no matter what.
                         */
                        } else {
-                               if (tick_before(frame + ed->interval *
-                                       (urb->number_of_packets - 1), next)) {
-                                       retval = -EXDEV;
-                                       usb_hcd_unlink_urb_from_ep(hcd, urb);
-                                       goto fail;
-                               }
-
                                /*
                                 * Some OHCI hardware doesn't handle late TDs
                                 * correctly.  After retiring them it proceeds
@@ -251,9 +246,16 @@ static int ohci_urb_enqueue (
                                urb_priv->td_cnt = DIV_ROUND_UP(
                                                (u16) (next - frame),
                                                ed->interval);
+                               if (urb_priv->td_cnt >= urb_priv->length) {
+                                       ++urb_priv->td_cnt;     /* Mark it */
+                                       ohci_dbg(ohci, "iso underrun %p (%u+%u < %u)\n",
+                                                       urb, frame, length,
+                                                       next);
+                               }
                        }
                }
                urb->start_frame = frame;
+               ed->last_iso = frame + length;
        }
 
        /* fill the TDs and link them to the ed; and
index df4a6707322d322dc292e4d11bfdf926e34dd3ce..e7f577e636240b25a74f6b5f4b43c9ebdc99e9de 100644 (file)
@@ -41,9 +41,13 @@ finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)
 __releases(ohci->lock)
 __acquires(ohci->lock)
 {
-        struct device *dev = ohci_to_hcd(ohci)->self.controller;
+       struct device *dev = ohci_to_hcd(ohci)->self.controller;
+       struct usb_host_endpoint *ep = urb->ep;
+       struct urb_priv *urb_priv;
+
        // ASSERT (urb->hcpriv != 0);
 
+ restart:
        urb_free_priv (ohci, urb->hcpriv);
        urb->hcpriv = NULL;
        if (likely(status == -EINPROGRESS))
@@ -80,6 +84,21 @@ __acquires(ohci->lock)
                ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE);
                ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
        }
+
+       /*
+        * An isochronous URB that is sumitted too late won't have any TDs
+        * (marked by the fact that the td_cnt value is larger than the
+        * actual number of TDs).  If the next URB on this endpoint is like
+        * that, give it back now.
+        */
+       if (!list_empty(&ep->urb_list)) {
+               urb = list_first_entry(&ep->urb_list, struct urb, urb_list);
+               urb_priv = urb->hcpriv;
+               if (urb_priv->td_cnt > urb_priv->length) {
+                       status = 0;
+                       goto restart;
+               }
+       }
 }
 
 
@@ -546,7 +565,6 @@ td_fill (struct ohci_hcd *ohci, u32 info,
                td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000);
                *ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci,
                                                (data & 0x0FFF) | 0xE000);
-               td->ed->last_iso = info & 0xffff;
        } else {
                td->hwCBP = cpu_to_hc32 (ohci, data);
        }
@@ -996,7 +1014,7 @@ rescan_this:
                        urb_priv->td_cnt++;
 
                        /* if URB is done, clean up */
-                       if (urb_priv->td_cnt == urb_priv->length) {
+                       if (urb_priv->td_cnt >= urb_priv->length) {
                                modified = completed = 1;
                                finish_urb(ohci, urb, 0);
                        }
@@ -1086,7 +1104,7 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td)
        urb_priv->td_cnt++;
 
        /* If all this urb's TDs are done, call complete() */
-       if (urb_priv->td_cnt == urb_priv->length)
+       if (urb_priv->td_cnt >= urb_priv->length)
                finish_urb(ohci, urb, status);
 
        /* clean schedule:  unlink EDs that are no longer busy */
index 2c76ef1320eab679e1dd1aabd1c8466981392efc..08ef2829a7e2b1c06bbd0af51f308884c8ad9a26 100644 (file)
@@ -799,7 +799,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)
         * switchable ports.
         */
        pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
-                       cpu_to_le32(ports_available));
+                       ports_available);
 
        pci_read_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
                        &ports_available);
@@ -821,7 +821,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)
         * host.
         */
        pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
-                       cpu_to_le32(ports_available));
+                       ports_available);
 
        pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
                        &ports_available);
index c300bd2f7d1c53e0ee684b0c6f9cab185fb1c55c..0f228c46eedaab97c9351f784b8604d6144bb517 100644 (file)
@@ -293,7 +293,7 @@ static struct pci_driver uhci_pci_driver = {
        .remove =       usb_hcd_pci_remove,
        .shutdown =     uhci_shutdown,
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
        .driver =       {
                .pm =   &usb_hcd_pci_pm_ops
        },
index 041c6ddb695c8ec6fa17d371fe7904de2e47d5ab..da6f56d996ce56f61cd1be20a093c2c16ff54702 100644 (file)
@@ -1303,7 +1303,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
                }
 
                /* Fell behind? */
-               if (uhci_frame_before_eq(frame, next)) {
+               if (!uhci_frame_before_eq(next, frame)) {
 
                        /* USB_ISO_ASAP: Round up to the first available slot */
                        if (urb->transfer_flags & URB_ISO_ASAP)
@@ -1311,13 +1311,17 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
                                                -qh->period;
 
                        /*
-                        * Not ASAP: Use the next slot in the stream.  If
-                        * the entire URB falls before the threshold, fail.
+                        * Not ASAP: Use the next slot in the stream,
+                        * no matter what.
                         */
                        else if (!uhci_frame_before_eq(next,
                                        frame + (urb->number_of_packets - 1) *
                                                qh->period))
-                               return -EXDEV;
+                               dev_dbg(uhci_dev(uhci), "iso underrun %p (%u+%u < %u)\n",
+                                               urb, frame,
+                                               (urb->number_of_packets - 1) *
+                                                       qh->period,
+                                               next);
                }
        }
 
index fae697ed0b708352e06e6e6135a2b49ece4ea34a..e8b4c56dcf62adf1f5326e8609087cd387fedc2e 100644 (file)
@@ -287,7 +287,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
                if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue)
                        xhci_queue_stop_endpoint(xhci, slot_id, i, suspend);
        }
-       cmd->command_trb = xhci->cmd_ring->enqueue;
+       cmd->command_trb = xhci_find_next_enqueue(xhci->cmd_ring);
        list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list);
        xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend);
        xhci_ring_cmd_db(xhci);
@@ -552,11 +552,15 @@ void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex)
  *  - Mark a port as being done with device resume,
  *    and ring the endpoint doorbells.
  *  - Stop the Synopsys redriver Compliance Mode polling.
+ *  - Drop and reacquire the xHCI lock, in order to wait for port resume.
  */
 static u32 xhci_get_port_status(struct usb_hcd *hcd,
                struct xhci_bus_state *bus_state,
                __le32 __iomem **port_array,
-               u16 wIndex, u32 raw_port_status)
+               u16 wIndex, u32 raw_port_status,
+               unsigned long flags)
+       __releases(&xhci->lock)
+       __acquires(&xhci->lock)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        u32 status = 0;
@@ -591,21 +595,42 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
                        return 0xffffffff;
                if (time_after_eq(jiffies,
                                        bus_state->resume_done[wIndex])) {
+                       int time_left;
+
                        xhci_dbg(xhci, "Resume USB2 port %d\n",
                                        wIndex + 1);
                        bus_state->resume_done[wIndex] = 0;
                        clear_bit(wIndex, &bus_state->resuming_ports);
+
+                       set_bit(wIndex, &bus_state->rexit_ports);
                        xhci_set_link_state(xhci, port_array, wIndex,
                                        XDEV_U0);
-                       xhci_dbg(xhci, "set port %d resume\n",
-                                       wIndex + 1);
-                       slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-                                       wIndex + 1);
-                       if (!slot_id) {
-                               xhci_dbg(xhci, "slot_id is zero\n");
-                               return 0xffffffff;
+
+                       spin_unlock_irqrestore(&xhci->lock, flags);
+                       time_left = wait_for_completion_timeout(
+                                       &bus_state->rexit_done[wIndex],
+                                       msecs_to_jiffies(
+                                               XHCI_MAX_REXIT_TIMEOUT));
+                       spin_lock_irqsave(&xhci->lock, flags);
+
+                       if (time_left) {
+                               slot_id = xhci_find_slot_id_by_port(hcd,
+                                               xhci, wIndex + 1);
+                               if (!slot_id) {
+                                       xhci_dbg(xhci, "slot_id is zero\n");
+                                       return 0xffffffff;
+                               }
+                               xhci_ring_device(xhci, slot_id);
+                       } else {
+                               int port_status = xhci_readl(xhci,
+                                               port_array[wIndex]);
+                               xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n",
+                                               XHCI_MAX_REXIT_TIMEOUT,
+                                               port_status);
+                               status |= USB_PORT_STAT_SUSPEND;
+                               clear_bit(wIndex, &bus_state->rexit_ports);
                        }
-                       xhci_ring_device(xhci, slot_id);
+
                        bus_state->port_c_suspend |= 1 << wIndex;
                        bus_state->suspended_ports &= ~(1 << wIndex);
                } else {
@@ -728,7 +753,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        break;
                }
                status = xhci_get_port_status(hcd, bus_state, port_array,
-                               wIndex, temp);
+                               wIndex, temp, flags);
                if (status == 0xffffffff)
                        goto error;
 
@@ -1132,18 +1157,6 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
                t1 = xhci_port_state_to_neutral(t1);
                if (t1 != t2)
                        xhci_writel(xhci, t2, port_array[port_index]);
-
-               if (hcd->speed != HCD_USB3) {
-                       /* enable remote wake up for USB 2.0 */
-                       __le32 __iomem *addr;
-                       u32 tmp;
-
-                       /* Get the port power control register address. */
-                       addr = port_array[port_index] + PORTPMSC;
-                       tmp = xhci_readl(xhci, addr);
-                       tmp |= PORT_RWE;
-                       xhci_writel(xhci, tmp, addr);
-               }
        }
        hcd->state = HC_STATE_SUSPENDED;
        bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
@@ -1222,20 +1235,6 @@ int xhci_bus_resume(struct usb_hcd *hcd)
                                xhci_ring_device(xhci, slot_id);
                } else
                        xhci_writel(xhci, temp, port_array[port_index]);
-
-               if (hcd->speed != HCD_USB3) {
-                       /* disable remote wake up for USB 2.0 */
-                       __le32 __iomem *addr;
-                       u32 tmp;
-
-                       /* Add one to the port status register address to get
-                        * the port power control register address.
-                        */
-                       addr = port_array[port_index] + PORTPMSC;
-                       tmp = xhci_readl(xhci, addr);
-                       tmp &= ~PORT_RWE;
-                       xhci_writel(xhci, tmp, addr);
-               }
        }
 
        (void) xhci_readl(xhci, &xhci->op_regs->command);
index 53b972c2a09f10be38a474042d03757618bc76a4..83bcd13622c3466e655a00166bf6e8076ae198bc 100644 (file)
@@ -2428,6 +2428,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        for (i = 0; i < USB_MAXCHILDREN; ++i) {
                xhci->bus_state[0].resume_done[i] = 0;
                xhci->bus_state[1].resume_done[i] = 0;
+               /* Only the USB 2.0 completions will ever be used. */
+               init_completion(&xhci->bus_state[1].rexit_done[i]);
        }
 
        if (scratchpad_alloc(xhci, flags))
index c2d495057eb538a74db9a01fc69af12442ca8d45..b8dffd59eb256e52786328e5e4f1919846a80d9c 100644 (file)
@@ -35,6 +35,9 @@
 #define PCI_VENDOR_ID_ETRON            0x1b6f
 #define PCI_DEVICE_ID_ASROCK_P67       0x7023
 
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI     0x8c31
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI  0x9c31
+
 static const char hcd_name[] = "xhci_hcd";
 
 /* called after powerup, by probe or system-pm "wakeup" */
@@ -69,6 +72,14 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                                "QUIRK: Fresco Logic xHC needs configure"
                                " endpoint cmd after reset endpoint");
                }
+               if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
+                               pdev->revision == 0x4) {
+                       xhci->quirks |= XHCI_SLOW_SUSPEND;
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "QUIRK: Fresco Logic xHC revision %u"
+                               "must be suspended extra slowly",
+                               pdev->revision);
+               }
                /* Fresco Logic confirms: all revisions of this chip do not
                 * support MSI, even though some of them claim to in their PCI
                 * capabilities.
@@ -110,6 +121,15 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                xhci->quirks |= XHCI_SPURIOUS_REBOOT;
                xhci->quirks |= XHCI_AVOID_BEI;
        }
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+           (pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI ||
+            pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI)) {
+               /* Workaround for occasional spurious wakeups from S5 (or
+                * any other sleep) on Haswell machines with LPT and LPT-LP
+                * with the new Intel BIOS
+                */
+               xhci->quirks |= XHCI_SPURIOUS_WAKEUP;
+       }
        if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
                        pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
                xhci->quirks |= XHCI_RESET_ON_RESUME;
@@ -217,6 +237,11 @@ static void xhci_pci_remove(struct pci_dev *dev)
                usb_put_hcd(xhci->shared_hcd);
        }
        usb_hcd_pci_remove(dev);
+
+       /* Workaround for spurious wakeups at shutdown with HSW */
+       if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
+               pci_set_power_state(dev, PCI_D3hot);
+
        kfree(xhci);
 }
 
@@ -351,7 +376,7 @@ static struct pci_driver xhci_pci_driver = {
        /* suspend and resume implemented later */
 
        .shutdown =     usb_hcd_pci_shutdown,
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
        .driver = {
                .pm = &usb_hcd_pci_pm_ops
        },
index 411da1fc7ae8ad0550df9cecb8d5a4bdab0fa543..6bfbd80ec2b9edfa0a079767381d7d733d8c7035 100644 (file)
@@ -123,6 +123,16 @@ static int enqueue_is_link_trb(struct xhci_ring *ring)
        return TRB_TYPE_LINK_LE32(link->control);
 }
 
+union xhci_trb *xhci_find_next_enqueue(struct xhci_ring *ring)
+{
+       /* Enqueue pointer can be left pointing to the link TRB,
+        * we must handle that
+        */
+       if (TRB_TYPE_LINK_LE32(ring->enqueue->link.control))
+               return ring->enq_seg->next->trbs;
+       return ring->enqueue;
+}
+
 /* Updates trb to point to the next TRB in the ring, and updates seg if the next
  * TRB is in a new segment.  This does not skip over link TRBs, and it does not
  * effect the ring dequeue or enqueue pointers.
@@ -859,8 +869,12 @@ remove_finished_td:
                /* Otherwise ring the doorbell(s) to restart queued transfers */
                ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
        }
-       ep->stopped_td = NULL;
-       ep->stopped_trb = NULL;
+
+       /* Clear stopped_td and stopped_trb if endpoint is not halted */
+       if (!(ep->ep_state & EP_HALTED)) {
+               ep->stopped_td = NULL;
+               ep->stopped_trb = NULL;
+       }
 
        /*
         * Drop the lock and complete the URBs in the cancelled TD list.
@@ -1414,6 +1428,12 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
                        inc_deq(xhci, xhci->cmd_ring);
                        return;
                }
+               /* There is no command to handle if we get a stop event when the
+                * command ring is empty, event->cmd_trb points to the next
+                * unset command
+                */
+               if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue)
+                       return;
        }
 
        switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])
@@ -1743,6 +1763,19 @@ static void handle_port_status(struct xhci_hcd *xhci,
                }
        }
 
+       /*
+        * Check to see if xhci-hub.c is waiting on RExit to U0 transition (or
+        * RExit to a disconnect state).  If so, let the the driver know it's
+        * out of the RExit state.
+        */
+       if (!DEV_SUPERSPEED(temp) &&
+                       test_and_clear_bit(faked_port_index,
+                               &bus_state->rexit_ports)) {
+               complete(&bus_state->rexit_done[faked_port_index]);
+               bogus_port_status = true;
+               goto cleanup;
+       }
+
        if (hcd->speed != HCD_USB3)
                xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
                                        PORT_PLC);
index 49b6edb84a79eccfd5f935db8e03bad0957ee5ad..6e0d886bcce52c19361d321cf68c0abacf5b054c 100644 (file)
@@ -730,6 +730,9 @@ void xhci_shutdown(struct usb_hcd *hcd)
 
        spin_lock_irq(&xhci->lock);
        xhci_halt(xhci);
+       /* Workaround for spurious wakeups at shutdown with HSW */
+       if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
+               xhci_reset(xhci);
        spin_unlock_irq(&xhci->lock);
 
        xhci_cleanup_msix(xhci);
@@ -737,6 +740,10 @@ void xhci_shutdown(struct usb_hcd *hcd)
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "xhci_shutdown completed - status = %x",
                        xhci_readl(xhci, &xhci->op_regs->status));
+
+       /* Yet another workaround for spurious wakeups at shutdown with HSW */
+       if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
+               pci_set_power_state(to_pci_dev(hcd->self.controller), PCI_D3hot);
 }
 
 #ifdef CONFIG_PM
@@ -839,6 +846,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
 int xhci_suspend(struct xhci_hcd *xhci)
 {
        int                     rc = 0;
+       unsigned int            delay = XHCI_MAX_HALT_USEC;
        struct usb_hcd          *hcd = xhci_to_hcd(xhci);
        u32                     command;
 
@@ -861,8 +869,12 @@ int xhci_suspend(struct xhci_hcd *xhci)
        command = xhci_readl(xhci, &xhci->op_regs->command);
        command &= ~CMD_RUN;
        xhci_writel(xhci, command, &xhci->op_regs->command);
+
+       /* Some chips from Fresco Logic need an extraordinary delay */
+       delay *= (xhci->quirks & XHCI_SLOW_SUSPEND) ? 10 : 1;
+
        if (xhci_handshake(xhci, &xhci->op_regs->status,
-                     STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) {
+                     STS_HALT, STS_HALT, delay)) {
                xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");
                spin_unlock_irq(&xhci->lock);
                return -ETIMEDOUT;
@@ -2598,15 +2610,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
        if (command) {
                cmd_completion = command->completion;
                cmd_status = &command->status;
-               command->command_trb = xhci->cmd_ring->enqueue;
-
-               /* Enqueue pointer can be left pointing to the link TRB,
-                * we must handle that
-                */
-               if (TRB_TYPE_LINK_LE32(command->command_trb->link.control))
-                       command->command_trb =
-                               xhci->cmd_ring->enq_seg->next->trbs;
-
+               command->command_trb = xhci_find_next_enqueue(xhci->cmd_ring);
                list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
        } else {
                cmd_completion = &virt_dev->cmd_completion;
@@ -2614,7 +2618,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
        }
        init_completion(cmd_completion);
 
-       cmd_trb = xhci->cmd_ring->dequeue;
+       cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring);
        if (!ctx_change)
                ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma,
                                udev->slot_id, must_succeed);
@@ -3439,14 +3443,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
 
        /* Attempt to submit the Reset Device command to the command ring */
        spin_lock_irqsave(&xhci->lock, flags);
-       reset_device_cmd->command_trb = xhci->cmd_ring->enqueue;
-
-       /* Enqueue pointer can be left pointing to the link TRB,
-        * we must handle that
-        */
-       if (TRB_TYPE_LINK_LE32(reset_device_cmd->command_trb->link.control))
-               reset_device_cmd->command_trb =
-                       xhci->cmd_ring->enq_seg->next->trbs;
+       reset_device_cmd->command_trb = xhci_find_next_enqueue(xhci->cmd_ring);
 
        list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list);
        ret = xhci_queue_reset_device(xhci, slot_id);
@@ -3650,7 +3647,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
        union xhci_trb *cmd_trb;
 
        spin_lock_irqsave(&xhci->lock, flags);
-       cmd_trb = xhci->cmd_ring->dequeue;
+       cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring);
        ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0);
        if (ret) {
                spin_unlock_irqrestore(&xhci->lock, flags);
@@ -3785,7 +3782,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
                                slot_ctx->dev_info >> 27);
 
        spin_lock_irqsave(&xhci->lock, flags);
-       cmd_trb = xhci->cmd_ring->dequeue;
+       cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring);
        ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma,
                                        udev->slot_id);
        if (ret) {
index 46aa14894148962e3aff6c8028f8d07cbcb07951..941d5f59e4dcc254770bac770ba024e36a677bad 100644 (file)
@@ -1412,8 +1412,18 @@ struct xhci_bus_state {
        unsigned long           resume_done[USB_MAXCHILDREN];
        /* which ports have started to resume */
        unsigned long           resuming_ports;
+       /* Which ports are waiting on RExit to U0 transition. */
+       unsigned long           rexit_ports;
+       struct completion       rexit_done[USB_MAXCHILDREN];
 };
 
+
+/*
+ * It can take up to 20 ms to transition from RExit to U0 on the
+ * Intel Lynx Point LP xHCI host.
+ */
+#define        XHCI_MAX_REXIT_TIMEOUT  (20 * 1000)
+
 static inline unsigned int hcd_index(struct usb_hcd *hcd)
 {
        if (hcd->speed == HCD_USB3)
@@ -1538,6 +1548,8 @@ struct xhci_hcd {
 #define XHCI_COMP_MODE_QUIRK   (1 << 14)
 #define XHCI_AVOID_BEI         (1 << 15)
 #define XHCI_PLAT              (1 << 16)
+#define XHCI_SLOW_SUSPEND      (1 << 17)
+#define XHCI_SPURIOUS_WAKEUP   (1 << 18)
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
        /* There are two roothubs to keep track of bus suspend info for */
@@ -1840,6 +1852,7 @@ int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
                union xhci_trb *cmd_trb);
 void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
                unsigned int ep_index, unsigned int stream_id);
+union xhci_trb *xhci_find_next_enqueue(struct xhci_ring *ring);
 
 /* xHCI roothub code */
 void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
index e2b21c1d9c403088d704d12901c8049e329c360f..ba5f70f92888774c5ef900d44c6f8ad941e6b4e9 100644 (file)
@@ -246,6 +246,6 @@ config USB_EZUSB_FX2
 config USB_HSIC_USB3503
        tristate "USB3503 HSIC to USB20 Driver"
        depends on I2C
-       select REGMAP
+       select REGMAP_I2C
        help
          This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver.
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 18e877ffe7b7d8c7393bdf43efdfd0d58e618011..cd70cc8861711015f5443e2b76e969209d9bdb3a 100644 (file)
@@ -921,6 +921,52 @@ static void musb_generic_disable(struct musb *musb)
 
 }
 
+/*
+ * Program the HDRC to start (enable interrupts, dma, etc.).
+ */
+void musb_start(struct musb *musb)
+{
+       void __iomem    *regs = musb->mregs;
+       u8              devctl = musb_readb(regs, MUSB_DEVCTL);
+
+       dev_dbg(musb->controller, "<== devctl %02x\n", devctl);
+
+       /*  Set INT enable registers, enable interrupts */
+       musb->intrtxe = musb->epmask;
+       musb_writew(regs, MUSB_INTRTXE, musb->intrtxe);
+       musb->intrrxe = musb->epmask & 0xfffe;
+       musb_writew(regs, MUSB_INTRRXE, musb->intrrxe);
+       musb_writeb(regs, MUSB_INTRUSBE, 0xf7);
+
+       musb_writeb(regs, MUSB_TESTMODE, 0);
+
+       /* put into basic highspeed mode and start session */
+       musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE
+                       | MUSB_POWER_HSENAB
+                       /* ENSUSPEND wedges tusb */
+                       /* | MUSB_POWER_ENSUSPEND */
+                  );
+
+       musb->is_active = 0;
+       devctl = musb_readb(regs, MUSB_DEVCTL);
+       devctl &= ~MUSB_DEVCTL_SESSION;
+
+       /* session started after:
+        * (a) ID-grounded irq, host mode;
+        * (b) vbus present/connect IRQ, peripheral mode;
+        * (c) peripheral initiates, using SRP
+        */
+       if (musb->port_mode != MUSB_PORT_MODE_HOST &&
+                       (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) {
+               musb->is_active = 1;
+       } else {
+               devctl |= MUSB_DEVCTL_SESSION;
+       }
+
+       musb_platform_enable(musb);
+       musb_writeb(regs, MUSB_DEVCTL, devctl);
+}
+
 /*
  * Make the HDRC stop (disable interrupts, etc.);
  * reversible by musb_start
index 65f3917b4fc5fb55c95bf4157d70a1d7194a110d..1c5bf75ee8ff8a45a3da1fca7cb1d31920f0eeff 100644 (file)
@@ -503,6 +503,7 @@ static inline void musb_configure_ep0(struct musb *musb)
 extern const char musb_driver_name[];
 
 extern void musb_stop(struct musb *musb);
+extern void musb_start(struct musb *musb);
 
 extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);
 extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst);
index 4047cbb91bac4e541b914801fe8e12c92d923625..bd4138d80a48f243c9d4cb32527196d0024eb3d1 100644 (file)
@@ -535,6 +535,9 @@ static int dsps_probe(struct platform_device *pdev)
        struct dsps_glue *glue;
        int ret;
 
+       if (!strcmp(pdev->name, "musb-hdrc"))
+               return -ENODEV;
+
        match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);
        if (!match) {
                dev_err(&pdev->dev, "fail to get matching of_match struct\n");
index 9a08679d204dfe9ee6fb1ad421813ea329c25abd..3671898a4535b3cf2de3c0e188f4947485d2760d 100644 (file)
@@ -1790,6 +1790,10 @@ int musb_gadget_setup(struct musb *musb)
        musb->g.max_speed = USB_SPEED_HIGH;
        musb->g.speed = USB_SPEED_UNKNOWN;
 
+       MUSB_DEV_MODE(musb);
+       musb->xceiv->otg->default_a = 0;
+       musb->xceiv->state = OTG_STATE_B_IDLE;
+
        /* this "gadget" abstracts/virtualizes the controller */
        musb->g.name = musb_driver_name;
        musb->g.is_otg = 1;
@@ -1855,6 +1859,8 @@ static int musb_gadget_start(struct usb_gadget *g,
        musb->xceiv->state = OTG_STATE_B_IDLE;
        spin_unlock_irqrestore(&musb->lock, flags);
 
+       musb_start(musb);
+
        /* REVISIT:  funcall to other code, which also
         * handles power budgeting ... this way also
         * ensures HdrcStart is indirectly called.
index a523950c2b32e66e07f7c8bd78daa181f691f25c..d1d6b83aabca61df43dffccf57ccbe7687cbe399 100644 (file)
 
 #include "musb_core.h"
 
-/*
-* Program the HDRC to start (enable interrupts, dma, etc.).
-*/
-static void musb_start(struct musb *musb)
-{
-       void __iomem    *regs = musb->mregs;
-       u8              devctl = musb_readb(regs, MUSB_DEVCTL);
-
-       dev_dbg(musb->controller, "<== devctl %02x\n", devctl);
-
-       /*  Set INT enable registers, enable interrupts */
-       musb->intrtxe = musb->epmask;
-       musb_writew(regs, MUSB_INTRTXE, musb->intrtxe);
-       musb->intrrxe = musb->epmask & 0xfffe;
-       musb_writew(regs, MUSB_INTRRXE, musb->intrrxe);
-       musb_writeb(regs, MUSB_INTRUSBE, 0xf7);
-
-       musb_writeb(regs, MUSB_TESTMODE, 0);
-
-       /* put into basic highspeed mode and start session */
-       musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE
-                                               | MUSB_POWER_HSENAB
-                                               /* ENSUSPEND wedges tusb */
-                                               /* | MUSB_POWER_ENSUSPEND */
-                                               );
-
-       musb->is_active = 0;
-       devctl = musb_readb(regs, MUSB_DEVCTL);
-       devctl &= ~MUSB_DEVCTL_SESSION;
-
-       /* session started after:
-        * (a) ID-grounded irq, host mode;
-        * (b) vbus present/connect IRQ, peripheral mode;
-        * (c) peripheral initiates, using SRP
-        */
-       if (musb->port_mode != MUSB_PORT_MODE_HOST &&
-           (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) {
-               musb->is_active = 1;
-       } else {
-               devctl |= MUSB_DEVCTL_SESSION;
-       }
-
-       musb_platform_enable(musb);
-       musb_writeb(regs, MUSB_DEVCTL, devctl);
-}
-
 static void musb_port_suspend(struct musb *musb, bool do_suspend)
 {
        struct usb_otg  *otg = musb->xceiv->otg;
index b2f29c9aebbfdb15e9e9be8004f2e8d7bf5ed60d..02799a5efcd448b8c38ee85de7cad8452ffbb617 100644 (file)
@@ -241,7 +241,7 @@ static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend)
 
 /* platform driver interface */
 
-static int __init gpio_vbus_probe(struct platform_device *pdev)
+static int gpio_vbus_probe(struct platform_device *pdev)
 {
        struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
        struct gpio_vbus_data *gpio_vbus;
@@ -349,7 +349,7 @@ err_gpio:
        return err;
 }
 
-static int __exit gpio_vbus_remove(struct platform_device *pdev)
+static int gpio_vbus_remove(struct platform_device *pdev)
 {
        struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
        struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
@@ -398,8 +398,6 @@ static const struct dev_pm_ops gpio_vbus_dev_pm_ops = {
 };
 #endif
 
-/* NOTE:  the gpio-vbus device may *NOT* be hotplugged */
-
 MODULE_ALIAS("platform:gpio-vbus");
 
 static struct platform_driver gpio_vbus_driver = {
@@ -410,10 +408,11 @@ static struct platform_driver gpio_vbus_driver = {
                .pm = &gpio_vbus_dev_pm_ops,
 #endif
        },
-       .remove  = __exit_p(gpio_vbus_remove),
+       .probe          = gpio_vbus_probe,
+       .remove         = gpio_vbus_remove,
 };
 
-module_platform_driver_probe(gpio_vbus_driver, gpio_vbus_probe);
+module_platform_driver(gpio_vbus_driver);
 
 MODULE_DESCRIPTION("simple GPIO controlled OTG transceiver driver");
 MODULE_AUTHOR("Philipp Zabel");
index fc15694d3031bbf83b76e932914e44251280d491..4e8a0405f956c478491a1ed6f18d65a9afc07e9a 100644 (file)
@@ -79,7 +79,7 @@ static struct usb_dpll_params *omap_usb3_get_dpll_params(unsigned long rate)
                        return &dpll_map[i].params;
        }
 
-       return 0;
+       return NULL;
 }
 
 static int omap_usb3_suspend(struct usb_phy *x, int suspend)
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 c454bfa22a106184bbaee567e4f49fbad5d8d057..ddb9c51f2c999c04a27aab9d7a2924c429205672 100644 (file)
@@ -60,7 +60,7 @@ config USB_SERIAL_SIMPLE
                - Suunto ANT+ USB device.
                - Fundamental Software dongle.
                - HP4x calculators
-               - a number of Motoroloa phones
+               - a number of Motorola phones
                - Siemens USB/MPI adapter.
                - ViVOtech ViVOpay USB device.
                - Infineon Modem Flashloader USB interface
index 1cf6f125f5f078624b41bd1256686d35f28ee4b7..acaee066b99aa10e5ecf2a8e75cffd31899b6507 100644 (file)
@@ -81,6 +81,7 @@ static void option_instat_callback(struct urb *urb);
 
 #define HUAWEI_VENDOR_ID                       0x12D1
 #define HUAWEI_PRODUCT_E173                    0x140C
+#define HUAWEI_PRODUCT_E1750                   0x1406
 #define HUAWEI_PRODUCT_K4505                   0x1464
 #define HUAWEI_PRODUCT_K3765                   0x1465
 #define HUAWEI_PRODUCT_K4605                   0x14C6
@@ -450,6 +451,10 @@ static void option_instat_callback(struct urb *urb);
 #define CHANGHONG_VENDOR_ID                    0x2077
 #define CHANGHONG_PRODUCT_CH690                        0x7001
 
+/* Inovia */
+#define INOVIA_VENDOR_ID                       0x20a6
+#define INOVIA_SEW858                          0x1105
+
 /* some devices interfaces need special handling due to a number of reasons */
 enum option_blacklist_reason {
                OPTION_BLACKLIST_NONE = 0,
@@ -567,6 +572,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff),
                .driver_info = (kernel_ulong_t) &net_intf1_blacklist },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1750, 0xff, 0xff, 0xff),
+               .driver_info = (kernel_ulong_t) &net_intf2_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1442, USB_CLASS_COMM, 0x02, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff),
@@ -686,6 +693,222 @@ static const struct usb_device_id option_ids[] = {
        { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) },
        { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7B) },
        { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x02) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x03) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x04) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x05) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x06) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x10) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x12) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x13) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x14) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x15) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x17) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x18) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x19) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x31) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x32) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x33) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x34) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x35) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x36) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x48) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x49) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x61) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x62) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x63) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x64) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x65) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x66) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x78) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x79) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x02) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x03) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x04) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x05) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x06) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x10) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x12) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x13) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x14) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x15) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x17) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x18) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x19) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x31) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x32) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x33) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x34) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x35) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x36) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x48) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x49) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x61) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x62) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x63) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x64) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x65) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x66) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x78) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x79) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x02) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x03) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x04) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x05) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x06) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x10) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x12) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x13) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x14) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x15) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x17) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x18) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x19) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x31) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x32) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x33) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x34) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x35) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x36) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x48) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x49) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x61) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x62) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x63) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x64) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x65) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x66) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x78) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x79) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x02) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x03) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x04) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x05) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x06) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x10) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x12) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x13) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x14) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x15) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x17) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x18) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x19) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x31) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x32) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x33) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x34) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x35) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x36) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x48) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x49) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x61) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x62) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x63) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x64) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x65) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x66) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x78) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x79) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7C) },
 
 
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
@@ -1254,7 +1477,9 @@ static const struct usb_device_id option_ids[] = {
 
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) },
-       { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200) },
+       { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200),
+               .driver_info = (kernel_ulong_t)&net_intf6_blacklist
+       },
        { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
        { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/
        { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) },
@@ -1342,6 +1567,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
+       { USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) },
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
index e7a84f0f517969fec4bbb59ac270eeb97fbf22d3..bedf8e47713be02dfc80b8a2e3512cb24a455a15 100644 (file)
@@ -139,6 +139,7 @@ enum pl2303_type {
        HX_TA,          /* HX(A) / X(A) / TA version  */ /* TODO: improve */
        HXD_EA_RA_SA,   /* HXD / EA / RA / SA version */ /* TODO: improve */
        TB,             /* TB version */
+       HX_CLONE,       /* Cheap and less functional clone of the HX chip */
 };
 /*
  * NOTE: don't know the difference between type 0 and type 1,
@@ -206,8 +207,23 @@ static int pl2303_startup(struct usb_serial *serial)
                 * the device descriptors of the X/HX, HXD, EA, RA, SA, TA, TB
                 */
                if (le16_to_cpu(serial->dev->descriptor.bcdDevice) == 0x300) {
-                       type = HX_TA;
-                       type_str = "X/HX/TA";
+                       /* Check if the device is a clone */
+                       pl2303_vendor_read(0x9494, 0, serial, buf);
+                       /*
+                        * NOTE: Not sure if this read is really needed.
+                        * The HX returns 0x00, the clone 0x02, but the Windows
+                        * driver seems to ignore the value and continues.
+                        */
+                       pl2303_vendor_write(0x0606, 0xaa, serial);
+                       pl2303_vendor_read(0x8686, 0, serial, buf);
+                       if (buf[0] != 0xaa) {
+                               type = HX_CLONE;
+                               type_str = "X/HX clone (limited functionality)";
+                       } else {
+                               type = HX_TA;
+                               type_str = "X/HX/TA";
+                       }
+                       pl2303_vendor_write(0x0606, 0x00, serial);
                } else if (le16_to_cpu(serial->dev->descriptor.bcdDevice)
                                                                     == 0x400) {
                        type = HXD_EA_RA_SA;
@@ -305,8 +321,9 @@ static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type,
 {
        /*
         * NOTE: Only the values defined in baud_sup are supported !
-        *       => if unsupported values are set, the PL2303 seems to
-        *          use 9600 baud (at least my PL2303X always does)
+        * => if unsupported values are set, the PL2303 uses 9600 baud instead
+        * => HX clones just don't work at unsupported baud rates < 115200 baud,
+        *    for baud rates > 115200 they run at 115200 baud
         */
        const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
                                 4800, 7200, 9600, 14400, 19200, 28800, 38400,
@@ -316,14 +333,14 @@ static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type,
         * NOTE: With the exception of type_0/1 devices, the following
         * additional baud rates are supported (tested with HX rev. 3A only):
         * 110*, 56000*, 128000, 134400, 161280, 201600, 256000*, 268800,
-        * 403200, 806400.      (*: not HX)
+        * 403200, 806400.      (*: not HX and HX clones)
         *
         * Maximum values: HXD, TB: 12000000; HX, TA: 6000000;
-        *                 type_0+1: 1228800; RA: 921600; SA: 115200
+        *                 type_0+1: 1228800; RA: 921600; HX clones, SA: 115200
         *
         * As long as we are not using this encoding method for anything else
-        * than the type_0+1 and HX chips, there is no point in complicating
-        * the code to support them.
+        * than the type_0+1, HX and HX clone chips, there is no point in
+        * complicating the code to support them.
         */
        int i;
 
@@ -347,6 +364,8 @@ static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type,
                baud = min_t(int, baud, 6000000);
        else if (type == type_0 || type == type_1)
                baud = min_t(int, baud, 1228800);
+       else if (type == HX_CLONE)
+               baud = min_t(int, baud, 115200);
        /* Direct (standard) baud rate encoding method */
        put_unaligned_le32(baud, buf);
 
@@ -359,7 +378,8 @@ static int pl2303_baudrate_encode_divisor(int baud, enum pl2303_type type,
        /*
         * Divisor based baud rate encoding method
         *
-        * NOTE: it's not clear if the type_0/1 chips support this method
+        * NOTE: HX clones do NOT support this method.
+        * It's not clear if the type_0/1 chips support it.
         *
         * divisor = 12MHz * 32 / baudrate = 2^A * B
         *
@@ -452,7 +472,7 @@ static void pl2303_encode_baudrate(struct tty_struct *tty,
         * 1) Direct method: encodes the baud rate value directly
         *    => supported by all chip types
         * 2) Divisor based method: encodes a divisor to a base value (12MHz*32)
-        *    => supported by HX chips (and likely not by type_0/1 chips)
+        *    => not supported by HX clones (and likely type_0/1 chips)
         *
         * NOTE: Although the divisor based baud rate encoding method is much
         * more flexible, some of the standard baud rate values can not be
@@ -460,7 +480,7 @@ static void pl2303_encode_baudrate(struct tty_struct *tty,
         * the device likely uses the same baud rate generator for both methods
         * so that there is likley no difference.
         */
-       if (type == type_0 || type == type_1)
+       if (type == type_0 || type == type_1 || type == HX_CLONE)
                baud = pl2303_baudrate_encode_direct(baud, type, buf);
        else
                baud = pl2303_baudrate_encode_divisor(baud, type, buf);
@@ -813,6 +833,7 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
        result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                                 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
                                 0, NULL, 0, 100);
+       /* NOTE: HX clones don't support sending breaks, -EPIPE is returned */
        if (result)
                dev_err(&port->dev, "error sending break = %d\n", result);
 }
index 760b78560f67fd7e7d905d53dff2cb7a46f2919f..c9a35697ebe9a6e131d5a9c145e5f3f3415dd5bf 100644 (file)
@@ -190,6 +190,7 @@ static struct usb_device_id ti_id_table_combined[] = {
        { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
        { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
        { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
+       { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
        { }     /* terminator */
 };
index 94d75edef77fdf34e4f5e341e5952e532f03f09e..18509e6c21ab84e7d3133f7a0e428ba462d2a24b 100644 (file)
@@ -211,8 +211,11 @@ static int slave_configure(struct scsi_device *sdev)
                /*
                 * Many devices do not respond properly to READ_CAPACITY_16.
                 * Tell the SCSI layer to try READ_CAPACITY_10 first.
+                * However some USB 3.0 drive enclosures return capacity
+                * modulo 2TB. Those must use READ_CAPACITY_16
                 */
-               sdev->try_rc_10_first = 1;
+               if (!(us->fflags & US_FL_NEEDS_CAP16))
+                       sdev->try_rc_10_first = 1;
 
                /* assume SPC3 or latter devices support sense size > 18 */
                if (sdev->scsi_level > SCSI_SPC_2)
index c015f2c16729c5b4030fc829fae9a3cfb90acde6..de32cfa5bfa6ca0772d0955ea83b9b98dd698ea5 100644 (file)
@@ -1925,6 +1925,13 @@ UNUSUAL_DEV(  0x1652, 0x6600, 0x0201, 0x0201,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Oliver Neukum <oneukum@suse.com> */
+UNUSUAL_DEV(  0x174c, 0x55aa, 0x0100, 0x0100,
+               "ASMedia",
+               "AS2105",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NEEDS_CAP16),
+
 /* Reported by Jesse Feddema <jdfeddema@gmail.com> */
 UNUSUAL_DEV(  0x177f, 0x0400, 0x0000, 0x0000,
                "Yarvik",
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 a9807dea3887af0afe44e545784f70d46efa40dd..4fb7a8f83c8a99ff8d3412a5328b2407c98409a8 100644 (file)
@@ -545,6 +545,8 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
        long npage;
        int ret = 0, prot = 0;
        uint64_t mask;
+       struct vfio_dma *dma = NULL;
+       unsigned long pfn;
 
        end = map->iova + map->size;
 
@@ -587,8 +589,6 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
        }
 
        for (iova = map->iova; iova < end; iova += size, vaddr += size) {
-               struct vfio_dma *dma = NULL;
-               unsigned long pfn;
                long i;
 
                /* Pin a contiguous chunk of memory */
@@ -597,16 +597,15 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
                if (npage <= 0) {
                        WARN_ON(!npage);
                        ret = (int)npage;
-                       break;
+                       goto out;
                }
 
                /* Verify pages are not already mapped */
                for (i = 0; i < npage; i++) {
                        if (iommu_iova_to_phys(iommu->domain,
                                               iova + (i << PAGE_SHIFT))) {
-                               vfio_unpin_pages(pfn, npage, prot, true);
                                ret = -EBUSY;
-                               break;
+                               goto out_unpin;
                        }
                }
 
@@ -616,8 +615,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
                if (ret) {
                        if (ret != -EBUSY ||
                            map_try_harder(iommu, iova, pfn, npage, prot)) {
-                               vfio_unpin_pages(pfn, npage, prot, true);
-                               break;
+                               goto out_unpin;
                        }
                }
 
@@ -672,9 +670,8 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
                        dma = kzalloc(sizeof(*dma), GFP_KERNEL);
                        if (!dma) {
                                iommu_unmap(iommu->domain, iova, size);
-                               vfio_unpin_pages(pfn, npage, prot, true);
                                ret = -ENOMEM;
-                               break;
+                               goto out_unpin;
                        }
 
                        dma->size = size;
@@ -685,16 +682,21 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
                }
        }
 
-       if (ret) {
-               struct vfio_dma *tmp;
-               iova = map->iova;
-               size = map->size;
-               while ((tmp = vfio_find_dma(iommu, iova, size))) {
-                       int r = vfio_remove_dma_overlap(iommu, iova,
-                                                       &size, tmp);
-                       if (WARN_ON(r || !size))
-                               break;
-               }
+       WARN_ON(ret);
+       mutex_unlock(&iommu->lock);
+       return ret;
+
+out_unpin:
+       vfio_unpin_pages(pfn, npage, prot, true);
+
+out:
+       iova = map->iova;
+       size = map->size;
+       while ((dma = vfio_find_dma(iommu, iova, size))) {
+               int r = vfio_remove_dma_overlap(iommu, iova,
+                                               &size, dma);
+               if (WARN_ON(r || !size))
+                       break;
        }
 
        mutex_unlock(&iommu->lock);
index 0c27c7df1b093e6ad64292a5211387a3103543e2..ce5221fa393a8db2ca9f4de61817ae230f3f0bc8 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,32 @@ 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");
+       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
+       if (tag < 0) {
+               pr_err("Unable to obtain tag for tcm_vhost_cmd\n");
                return ERR_PTR(-ENOMEM);
        }
+
+       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 +758,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 +771,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 +814,6 @@ vhost_scsi_map_to_sgl(struct scatterlist *sgl,
        }
 
 out:
-       kfree(pages);
        return ret;
 }
 
@@ -807,24 +837,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 +1015,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;
                }
@@ -1352,21 +1378,30 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
        return 0;
 }
 
+static void vhost_scsi_free(struct vhost_scsi *vs)
+{
+       if (is_vmalloc_addr(vs))
+               vfree(vs);
+       else
+               kfree(vs);
+}
+
 static int vhost_scsi_open(struct inode *inode, struct file *f)
 {
        struct vhost_scsi *vs;
        struct vhost_virtqueue **vqs;
-       int r, i;
+       int r = -ENOMEM, i;
 
-       vs = kzalloc(sizeof(*vs), GFP_KERNEL);
-       if (!vs)
-               return -ENOMEM;
+       vs = kzalloc(sizeof(*vs), GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
+       if (!vs) {
+               vs = vzalloc(sizeof(*vs));
+               if (!vs)
+                       goto err_vs;
+       }
 
        vqs = kmalloc(VHOST_SCSI_MAX_VQ * sizeof(*vqs), GFP_KERNEL);
-       if (!vqs) {
-               kfree(vs);
-               return -ENOMEM;
-       }
+       if (!vqs)
+               goto err_vqs;
 
        vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work);
        vhost_work_init(&vs->vs_event_work, tcm_vhost_evt_work);
@@ -1386,14 +1421,18 @@ static int vhost_scsi_open(struct inode *inode, struct file *f)
 
        tcm_vhost_init_inflight(vs, NULL);
 
-       if (r < 0) {
-               kfree(vqs);
-               kfree(vs);
-               return r;
-       }
+       if (r < 0)
+               goto err_init;
 
        f->private_data = vs;
        return 0;
+
+err_init:
+       kfree(vqs);
+err_vqs:
+       vhost_scsi_free(vs);
+err_vs:
+       return r;
 }
 
 static int vhost_scsi_release(struct inode *inode, struct file *f)
@@ -1410,7 +1449,7 @@ static int vhost_scsi_release(struct inode *inode, struct file *f)
        /* Jobs can re-queue themselves in evt kick handler. Do extra flush. */
        vhost_scsi_flush(vs);
        kfree(vs->dev.vqs);
-       kfree(vs);
+       vhost_scsi_free(vs);
        return 0;
 }
 
@@ -1654,11 +1693,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 +1734,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 +1776,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 +1788,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 +1833,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 9a9502a4aa5089519d338ca62b07a557069fb00d..69068e0d8f31af183c075afe3026d60b09a0b55e 100644 (file)
@@ -161,9 +161,11 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
        if (list_empty(&work->node)) {
                list_add_tail(&work->node, &dev->work_list);
                work->queue_seq++;
+               spin_unlock_irqrestore(&dev->work_lock, flags);
                wake_up_process(dev->worker);
+       } else {
+               spin_unlock_irqrestore(&dev->work_lock, flags);
        }
-       spin_unlock_irqrestore(&dev->work_lock, flags);
 }
 EXPORT_SYMBOL_GPL(vhost_work_queue);
 
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 75dca19bf2149a968f733ed1ff8a0cd468baa745..6ac755270ab46d1a3ef830c89338c0daab519664 100644 (file)
@@ -514,7 +514,7 @@ static int mmphw_probe(struct platform_device *pdev)
        if (IS_ERR(ctrl->clk)) {
                dev_err(ctrl->dev, "unable to get clk %s\n", mi->clk_name);
                ret = -ENOENT;
-               goto failed_get_clk;
+               goto failed;
        }
        clk_prepare_enable(ctrl->clk);
 
@@ -551,21 +551,8 @@ failed_path_init:
                path_deinit(path_plat);
        }
 
-       if (ctrl->clk) {
-               devm_clk_put(ctrl->dev, ctrl->clk);
-               clk_disable_unprepare(ctrl->clk);
-       }
-failed_get_clk:
-       devm_free_irq(ctrl->dev, ctrl->irq, ctrl);
+       clk_disable_unprepare(ctrl->clk);
 failed:
-       if (ctrl) {
-               if (ctrl->reg_base)
-                       devm_iounmap(ctrl->dev, ctrl->reg_base);
-               devm_release_mem_region(ctrl->dev, res->start,
-                               resource_size(res));
-               devm_kfree(ctrl->dev, ctrl);
-       }
-
        dev_err(&pdev->dev, "device init failed\n");
 
        return ret;
index d250ed0f806d3bf66d858e9f633852f3baa58f4d..27197a8048c0a7aa9ffcbd3c8a2280ae12866dcc 100644 (file)
@@ -620,6 +620,7 @@ static int mxsfb_restore_mode(struct mxsfb_info *host)
                break;
        case 3:
                bits_per_pixel = 32;
+               break;
        case 1:
        default:
                return -EINVAL;
index 7ef079c146e7242c9edee33cc43bc0cd3c850ce1..c172a5281f9e6c9369b0cec236e3bbf2abb875ac 100644 (file)
@@ -2075,6 +2075,7 @@ static int neofb_probe(struct pci_dev *dev, const struct pci_device_id *id)
        if (!fb_find_mode(&info->var, info, mode_option, NULL, 0,
                        info->monspecs.modedb, 16)) {
                printk(KERN_ERR "neofb: Unable to find usable video mode.\n");
+               err = -EINVAL;
                goto err_map_video;
        }
 
@@ -2097,7 +2098,8 @@ static int neofb_probe(struct pci_dev *dev, const struct pci_device_id *id)
               info->fix.smem_len >> 10, info->var.xres,
               info->var.yres, h_sync / 1000, h_sync % 1000, v_sync);
 
-       if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+       err = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (err < 0)
                goto err_map_video;
 
        err = register_framebuffer(info);
index 171821ddd78de381a866e9912bece023a8fcaca5..ba5b40f581f6fdfe1849a3d4d62c8f38ea65dab1 100644 (file)
@@ -120,7 +120,7 @@ int of_get_display_timing(struct device_node *np, const char *name,
                return -EINVAL;
        }
 
-       timing_np = of_find_node_by_name(np, name);
+       timing_np = of_get_child_by_name(np, name);
        if (!timing_np) {
                pr_err("%s: could not find node '%s'\n",
                        of_node_full_name(np), name);
@@ -143,11 +143,11 @@ struct display_timings *of_get_display_timings(struct device_node *np)
        struct display_timings *disp;
 
        if (!np) {
-               pr_err("%s: no devicenode given\n", of_node_full_name(np));
+               pr_err("%s: no device node given\n", of_node_full_name(np));
                return NULL;
        }
 
-       timings_np = of_find_node_by_name(np, "display-timings");
+       timings_np = of_get_child_by_name(np, "display-timings");
        if (!timings_np) {
                pr_err("%s: could not find display-timings node\n",
                        of_node_full_name(np));
index 6c90885b094020f33b74d591db6a93edcbd4aeb7..10b25e7cd878c6e7a5657fd8c1a4865b0935c004 100644 (file)
@@ -35,6 +35,7 @@ config DISPLAY_PANEL_DPI
 
 config DISPLAY_PANEL_DSI_CM
        tristate "Generic DSI Command Mode Panel"
+       depends on BACKLIGHT_CLASS_DEVICE
        help
          Driver for generic DSI command mode panels.
 
index 1b60698f141ed983e2661743f2a5c79f471a02a6..ccd9073f706f6d59242a5b1866d74dcd2c9bffa6 100644 (file)
@@ -191,7 +191,7 @@ static int tvc_probe_pdata(struct platform_device *pdev)
        in = omap_dss_find_output(pdata->source);
        if (in == NULL) {
                dev_err(&pdev->dev, "Failed to find video source\n");
-               return -ENODEV;
+               return -EPROBE_DEFER;
        }
 
        ddata->in = in;
index bc5f8ceda371b1b26308db7c644c6913445c8b18..63d88ee6dfe410469215455795bd4b63b031a040 100644 (file)
@@ -263,7 +263,7 @@ static int dvic_probe_pdata(struct platform_device *pdev)
        in = omap_dss_find_output(pdata->source);
        if (in == NULL) {
                dev_err(&pdev->dev, "Failed to find video source\n");
-               return -ENODEV;
+               return -EPROBE_DEFER;
        }
 
        ddata->in = in;
index c5826716d6abbb8b28e85ccd1d70aaa8c0058b44..9abe2c039ae9c44f0ea2cb2a3362c021e9273df4 100644 (file)
@@ -290,7 +290,7 @@ static int hdmic_probe_pdata(struct platform_device *pdev)
        in = omap_dss_find_output(pdata->source);
        if (in == NULL) {
                dev_err(&pdev->dev, "Failed to find video source\n");
-               return -ENODEV;
+               return -EPROBE_DEFER;
        }
 
        ddata->in = in;
index 02a7340111dfbf4b856122aae670bdbff2c34150..477975009eee87e89c34cc773e2d5a8818f918d6 100644 (file)
@@ -3691,6 +3691,7 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
+       pm_runtime_irq_safe(&pdev->dev);
 
        r = dispc_runtime_get();
        if (r)
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 47ca86c5c6c0b3d1d609a001210e5eb132616076..d838ba829459400acc86388cbeda1bab77f57b24 100644 (file)
@@ -1336,14 +1336,7 @@ static int s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
                        (info->var.bits_per_pixel * info->var.xres_virtual);
        if (info->var.yres_virtual < info->var.yres) {
                dev_err(info->device, "virtual vertical size smaller than real\n");
-               goto err_find_mode;
-       }
-
-       /* maximize virtual vertical size for fast scrolling */
-       info->var.yres_virtual = info->fix.smem_len * 8 /
-                       (info->var.bits_per_pixel * info->var.xres_virtual);
-       if (info->var.yres_virtual < info->var.yres) {
-               dev_err(info->device, "virtual vertical size smaller than real\n");
+               rc = -EINVAL;
                goto err_find_mode;
        }
 
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..fa932c2f7d97276b66199eda06b6edb6565208bb 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;
@@ -609,6 +613,9 @@ static int w1_bus_notify(struct notifier_block *nb, unsigned long action,
        sl = dev_to_w1_slave(dev);
        fops = sl->family->fops;
 
+       if (!fops)
+               return 0;
+
        switch (action) {
        case BUS_NOTIFY_ADD_DEVICE:
                /* if the family driver needs to initialize something... */
@@ -709,7 +716,10 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
        atomic_set(&sl->refcnt, 0);
        init_completion(&sl->released);
 
+       /* slave modules need to be loaded in a context with unlocked mutex */
+       mutex_unlock(&dev->mutex);
        request_module("w1-family-0x%0x", rn->family);
+       mutex_lock(&dev->mutex);
 
        spin_lock(&w1_flock);
        f = w1_family_registered(rn->family);
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..19f3c3fc65f4c9af0ffa4a25cf8410e308a5fda8 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"
@@ -800,6 +802,12 @@ static int hpwdt_init_one(struct pci_dev *dev,
                return -ENODEV;
        }
 
+       /*
+        * Ignore all auxilary iLO devices with the following PCI ID
+        */
+       if (dev->subsystem_device == 0x1979)
+               return -ENODEV;
+
        if (pci_enable_device(dev)) {
                dev_warn(&dev->dev,
                        "Not possible to enable PCI Device: 0x%x:0x%x.\n",
index 491419e0772a83f89ae34f16a96750d2349407d1..5c3d4df63e6835f534cb57a3eca724ce08c3ba47 100644 (file)
@@ -35,7 +35,7 @@
 #define KEMPLD_WDT_STAGE_TIMEOUT(x)    (0x1b + (x) * 4)
 #define KEMPLD_WDT_STAGE_CFG(x)                (0x18 + (x))
 #define STAGE_CFG_GET_PRESCALER(x)     (((x) & 0x30) >> 4)
-#define STAGE_CFG_SET_PRESCALER(x)     (((x) & 0x30) << 4)
+#define STAGE_CFG_SET_PRESCALER(x)     (((x) & 0x3) << 4)
 #define STAGE_CFG_PRESCALER_MASK       0x30
 #define STAGE_CFG_ACTION_MASK          0x7
 #define STAGE_CFG_ASSERT               (1 << 3)
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..f6caa77
--- /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 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 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..c9b0c627fe7e6d8513dd4d43ba18cb65cfbba132 100644 (file)
@@ -310,7 +310,8 @@ static long ts72xx_wdt_ioctl(struct file *file, unsigned int cmd,
 
        case WDIOC_GETSTATUS:
        case WDIOC_GETBOOTSTATUS:
-               return put_user(0, p);
+               error = put_user(0, p);
+               break;
 
        case WDIOC_KEEPALIVE:
                ts72xx_wdt_kick(wdt);
@@ -403,21 +404,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..b232908a61925724bb61bc0f8a09ecbca6b753e6 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,
@@ -412,34 +411,35 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
 
                scrub_page(page);
 
+               /*
+                * Ballooned out frames are effectively replaced with
+                * a scratch frame.  Ensure direct mappings and the
+                * p2m are consistent.
+                */
+               scratch_page = get_balloon_scratch_page();
 #ifdef CONFIG_XEN_HAVE_PVMMU
                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);
                }
 #endif
-       }
-
-       /* Ensure that ballooned highmem pages don't have kmaps. */
-       kmap_flush_unused();
-       flush_tlb_all();
-
-       /* No more mappings: invalidate P2M and add to balloon. */
-       for (i = 0; i < nr_pages; i++) {
-               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));
                }
+               put_balloon_scratch_page();
+
                balloon_append(pfn_to_page(pfn));
        }
 
+       /* Ensure that ballooned highmem pages don't have kmaps. */
+       kmap_flush_unused();
+       flush_tlb_all();
+
        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 34494fbead0ab892733afb344e002ab1c9a08994..529300327f4574d2dc36345be3c7398442548e08 100644 (file)
@@ -600,9 +600,6 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
 
        /* lock down the parent dentry so we can peer at it */
        parent = dget_parent(dentry);
-       if (!parent->d_inode)
-               goto out_bad;
-
        dir = AFS_FS_I(parent->d_inode);
 
        /* validate the parent directory */
@@ -685,16 +682,12 @@ not_found:
        spin_unlock(&dentry->d_lock);
 
 out_bad:
-       if (dentry->d_inode) {
-               /* don't unhash if we have submounts */
-               if (have_submounts(dentry))
-                       goto out_skip;
-       }
+       /* don't unhash if we have submounts */
+       if (check_submounts_and_drop(dentry) != 0)
+               goto out_skip;
 
        _debug("dropping dentry %s/%s",
               parent->d_name.name, dentry->d_name.name);
-       shrink_dcache_parent(dentry);
-       d_drop(dentry);
        dput(parent);
        key_put(key);
 
@@ -755,10 +748,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);
@@ -820,10 +809,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);
@@ -940,10 +925,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);
@@ -1009,10 +990,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);
@@ -1057,10 +1034,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;
@@ -1131,10 +1104,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..067e3d340c353e614787fe5dbdb205dedb7b9ec4 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----*/
@@ -136,17 +167,102 @@ static int __init aio_setup(void)
 }
 __initcall(aio_setup);
 
+static void put_aio_ring_file(struct kioctx *ctx)
+{
+       struct file *aio_ring_file = ctx->aio_ring_file;
+       if (aio_ring_file) {
+               truncate_setsize(aio_ring_file->f_inode, 0);
+
+               /* Prevent further access to the kioctx from migratepages */
+               spin_lock(&aio_ring_file->f_inode->i_mapping->private_lock);
+               aio_ring_file->f_inode->i_mapping->private_data = NULL;
+               ctx->aio_ring_file = NULL;
+               spin_unlock(&aio_ring_file->f_inode->i_mapping->private_lock);
+
+               fput(aio_ring_file);
+       }
+}
+
 static void aio_free_ring(struct kioctx *ctx)
 {
-       long i;
+       int i;
 
-       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]);
+       }
+
+       put_aio_ring_file(ctx);
 
        if (ctx->ring_pages && ctx->ring_pages != ctx->internal_pages)
                kfree(ctx->ring_pages);
 }
 
+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;
+       unsigned long flags;
+       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);
+
+       /* We can potentially race against kioctx teardown here.  Use the
+        * address_space's private data lock to protect the mapping's
+        * private_data.
+        */
+       spin_lock(&mapping->private_lock);
+       ctx = mapping->private_data;
+       if (ctx) {
+               pgoff_t idx;
+               spin_lock_irqsave(&ctx->completion_lock, flags);
+               migrate_page_copy(new, old);
+               idx = old->index;
+               if (idx < (pgoff_t)ctx->nr_pages)
+                       ctx->ring_pages[idx] = new;
+               spin_unlock_irqrestore(&ctx->completion_lock, flags);
+       } else
+               rc = -EBUSY;
+       spin_unlock(&mapping->private_lock);
+
+       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 +270,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 +319,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 +332,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 +391,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 +403,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 +425,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 +440,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);
+
+               atomic_add(kcpu->reqs_available, &ctx->reqs_available);
+               kcpu->reqs_available = 0;
+       }
 
-       while (atomic_read(&ctx->reqs_active) > 0) {
-               wait_event(ctx->wait,
-                               head != ctx->tail ||
-                               atomic_read(&ctx->reqs_active) <= 0);
+       while (1) {
+               prepare_to_wait(&ctx->wait, &wait, TASK_UNINTERRUPTIBLE);
 
-               avail = (head <= ctx->tail ? ctx->tail : ctx->nr_events) - head;
+               ring = kmap_atomic(ctx->ring_pages[0]);
+               avail = (ring->head <= ring->tail)
+                        ? ring->tail - ring->head
+                        : ctx->nr_events - ring->head + ring->tail;
 
-               atomic_sub(avail, &ctx->reqs_active);
-               head += avail;
-               head %= ctx->nr_events;
+               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 +487,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 +560,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 +579,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 +588,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 +598,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 +620,53 @@ 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:
+       put_aio_ring_file(ctx);
        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 +683,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 +713,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 +745,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 +823,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 +872,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 +893,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 +945,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 +971,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 +979,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 +992,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 +1024,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 +1124,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 +1142,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 +1181,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 +1200,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 +1232,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 +1285,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 +1359,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 +1423,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 +1480,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 +1497,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 +1541,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 100edcc5e3122323eb8f4087305e623c666eceb0..4c94a79991bb6d8ae0d2e12ae8c647e2fe22f7fe 100644 (file)
@@ -1413,7 +1413,7 @@ static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
  *   long file_ofs
  * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
  */
-static void fill_files_note(struct memelfnote *note)
+static int fill_files_note(struct memelfnote *note)
 {
        struct vm_area_struct *vma;
        unsigned count, size, names_ofs, remaining, n;
@@ -1428,11 +1428,11 @@ static void fill_files_note(struct memelfnote *note)
        names_ofs = (2 + 3 * count) * sizeof(data[0]);
  alloc:
        if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */
-               goto err;
+               return -EINVAL;
        size = round_up(size, PAGE_SIZE);
        data = vmalloc(size);
        if (!data)
-               goto err;
+               return -ENOMEM;
 
        start_end_ofs = data + 2;
        name_base = name_curpos = ((char *)data) + names_ofs;
@@ -1485,7 +1485,7 @@ static void fill_files_note(struct memelfnote *note)
 
        size = name_curpos - (char *)data;
        fill_note(note, "CORE", NT_FILE, size, data);
err: ;
      return 0;
 }
 
 #ifdef CORE_DUMP_USE_REGSET
@@ -1686,8 +1686,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
        fill_auxv_note(&info->auxv, current->mm);
        info->size += notesize(&info->auxv);
 
-       fill_files_note(&info->files);
-       info->size += notesize(&info->files);
+       if (fill_files_note(&info->files) == 0)
+               info->size += notesize(&info->files);
 
        return 1;
 }
@@ -1719,7 +1719,8 @@ static int write_note_info(struct elf_note_info *info,
                        return 0;
                if (first && !writenote(&info->auxv, file, foffset))
                        return 0;
-               if (first && !writenote(&info->files, file, foffset))
+               if (first && info->files.data &&
+                               !writenote(&info->files, file, foffset))
                        return 0;
 
                for (i = 1; i < info->thread_notes; ++i)
@@ -1806,6 +1807,7 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
 
 struct elf_note_info {
        struct memelfnote *notes;
+       struct memelfnote *notes_files;
        struct elf_prstatus *prstatus;  /* NT_PRSTATUS */
        struct elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
        struct list_head thread_list;
@@ -1896,9 +1898,12 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
 
        fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo);
        fill_auxv_note(info->notes + 3, current->mm);
-       fill_files_note(info->notes + 4);
+       info->numnote = 4;
 
-       info->numnote = 5;
+       if (fill_files_note(info->notes + info->numnote) == 0) {
+               info->notes_files = info->notes + info->numnote;
+               info->numnote++;
+       }
 
        /* Try to dump the FPU. */
        info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs,
@@ -1960,8 +1965,9 @@ static void free_note_info(struct elf_note_info *info)
                kfree(list_entry(tmp, struct elf_thread_status, list));
        }
 
-       /* Free data allocated by fill_files_note(): */
-       vfree(info->notes[4].data);
+       /* Free data possibly allocated by fill_files_note(): */
+       if (info->notes_files)
+               vfree(info->notes_files->data);
 
        kfree(info->prstatus);
        kfree(info->psinfo);
@@ -2044,7 +2050,7 @@ static int elf_core_dump(struct coredump_params *cprm)
        struct vm_area_struct *vma, *gate_vma;
        struct elfhdr *elf = NULL;
        loff_t offset = 0, dataoff, foffset;
-       struct elf_note_info info;
+       struct elf_note_info info = { };
        struct elf_phdr *phdr4note = NULL;
        struct elf_shdr *shdr4extnum = NULL;
        Elf_Half e_phnum;
index 8fb42916d8a29812e349fdbfa980ef1c34056ce4..fc60b31453eefbbdcc234c7df78c5504da655980 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;
 }
@@ -734,7 +735,7 @@ void bioset_integrity_free(struct bio_set *bs)
                mempool_destroy(bs->bio_integrity_pool);
 
        if (bs->bvec_integrity_pool)
-               mempool_destroy(bs->bio_integrity_pool);
+               mempool_destroy(bs->bvec_integrity_pool);
 }
 EXPORT_SYMBOL(bioset_integrity_free);
 
index b3b20ed9510e5ccc285195cce7aa7e3f524ed063..ea5035da4d9a0cd9fd6f5f657bb01272c63175c3 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -917,8 +917,8 @@ void bio_copy_data(struct bio *dst, struct bio *src)
                src_p = kmap_atomic(src_bv->bv_page);
                dst_p = kmap_atomic(dst_bv->bv_page);
 
-               memcpy(dst_p + dst_bv->bv_offset,
-                      src_p + src_bv->bv_offset,
+               memcpy(dst_p + dst_offset,
+                      src_p + src_offset,
                       bytes);
 
                kunmap_atomic(dst_p);
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 58b7d14b08ee1d47ec66a06243ee16f63854b676..08cc08f037a633199bffb3fadfa95750302eb25e 100644 (file)
@@ -107,7 +107,8 @@ static void check_idle_worker(struct btrfs_worker_thread *worker)
                worker->idle = 1;
 
                /* the list may be empty if the worker is just starting */
-               if (!list_empty(&worker->worker_list)) {
+               if (!list_empty(&worker->worker_list) &&
+                   !worker->workers->stopping) {
                        list_move(&worker->worker_list,
                                 &worker->workers->idle_list);
                }
@@ -127,7 +128,8 @@ static void check_busy_worker(struct btrfs_worker_thread *worker)
                spin_lock_irqsave(&worker->workers->lock, flags);
                worker->idle = 0;
 
-               if (!list_empty(&worker->worker_list)) {
+               if (!list_empty(&worker->worker_list) &&
+                   !worker->workers->stopping) {
                        list_move_tail(&worker->worker_list,
                                      &worker->workers->worker_list);
                }
@@ -412,6 +414,7 @@ void btrfs_stop_workers(struct btrfs_workers *workers)
        int can_stop;
 
        spin_lock_irq(&workers->lock);
+       workers->stopping = 1;
        list_splice_init(&workers->idle_list, &workers->worker_list);
        while (!list_empty(&workers->worker_list)) {
                cur = workers->worker_list.next;
@@ -455,6 +458,7 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max,
        workers->ordered = 0;
        workers->atomic_start_pending = 0;
        workers->atomic_worker_start = async_helper;
+       workers->stopping = 0;
 }
 
 /*
@@ -480,15 +484,19 @@ static int __btrfs_start_workers(struct btrfs_workers *workers)
        atomic_set(&worker->num_pending, 0);
        atomic_set(&worker->refs, 1);
        worker->workers = workers;
-       worker->task = kthread_run(worker_loop, worker,
-                                  "btrfs-%s-%d", workers->name,
-                                  workers->num_workers + 1);
+       worker->task = kthread_create(worker_loop, worker,
+                                     "btrfs-%s-%d", workers->name,
+                                     workers->num_workers + 1);
        if (IS_ERR(worker->task)) {
                ret = PTR_ERR(worker->task);
-               kfree(worker);
                goto fail;
        }
+
        spin_lock_irq(&workers->lock);
+       if (workers->stopping) {
+               spin_unlock_irq(&workers->lock);
+               goto fail_kthread;
+       }
        list_add_tail(&worker->worker_list, &workers->idle_list);
        worker->idle = 1;
        workers->num_workers++;
@@ -496,8 +504,13 @@ static int __btrfs_start_workers(struct btrfs_workers *workers)
        WARN_ON(workers->num_workers_starting < 0);
        spin_unlock_irq(&workers->lock);
 
+       wake_up_process(worker->task);
        return 0;
+
+fail_kthread:
+       kthread_stop(worker->task);
 fail:
+       kfree(worker);
        spin_lock_irq(&workers->lock);
        workers->num_workers_starting--;
        spin_unlock_irq(&workers->lock);
index 063698b90ce2dd0481663aeee46b30ef796d52e2..1f26792683edf195b48db80992c05acae6fd71f0 100644 (file)
@@ -107,6 +107,8 @@ struct btrfs_workers {
 
        /* extra name for this worker, used for current->name */
        char *name;
+
+       int stopping;
 };
 
 void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work);
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..71f074e1870b2e9fe183cf338ad2515314155e6e 100644 (file)
@@ -213,11 +213,35 @@ static inline bool btrfs_is_free_space_inode(struct inode *inode)
 static inline int btrfs_inode_in_log(struct inode *inode, u64 generation)
 {
        if (BTRFS_I(inode)->logged_trans == generation &&
-           BTRFS_I(inode)->last_sub_trans <= BTRFS_I(inode)->last_log_commit)
+           BTRFS_I(inode)->last_sub_trans <=
+           BTRFS_I(inode)->last_log_commit &&
+           BTRFS_I(inode)->last_sub_trans <=
+           BTRFS_I(inode)->root->last_log_commit)
                return 1;
        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..61b5bcd57b7e320624c2778d2051db03b79f2282 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);
@@ -1056,8 +1005,11 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                return ret;
        }
 
-       if (root->ref_cows)
-               btrfs_reloc_cow_block(trans, root, buf, cow);
+       if (root->ref_cows) {
+               ret = btrfs_reloc_cow_block(trans, root, buf, cow);
+               if (ret)
+                       return ret;
+       }
 
        if (buf == root->node) {
                WARN_ON(parent && parent != buf);
@@ -1083,7 +1035,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 +1068,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 +1079,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 +1192,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 +1208,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 +1227,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 +1299,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 +1384,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 +2429,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 +2491,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 +2522,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 +2623,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 +2758,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 +2769,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 +2787,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 +2821,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 +3148,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 +3211,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 +3287,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 +4042,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 +4643,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 +4815,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 +5330,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..0506f40ede8331f8ab7b20a4d2778e49c886fe91 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__));
@@ -1113,15 +1118,6 @@ struct btrfs_space_info {
         */
        struct percpu_counter total_bytes_pinned;
 
-       /*
-        * we bump reservation progress every time we decrement
-        * bytes_reserved.  This way people waiting for reservations
-        * know something good has happened and they can check
-        * for progress.  The number here isn't to be trusted, it
-        * just shows reclaim activity
-        */
-       unsigned long reservation_progress;
-
        unsigned int full:1;    /* indicates that we cannot allocate any more
                                   chunks for this space */
        unsigned int chunk_alloc:1;     /* set if we are allocating a chunk */
@@ -1188,6 +1184,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 +1299,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 +1348,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 +1410,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 +1647,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 +1942,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 +1989,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 +2155,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 +2265,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 +2309,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 +2321,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 +2392,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 +2452,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 +2516,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 +2625,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 +2666,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 +2891,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 +2911,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)
@@ -3054,7 +3126,7 @@ static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root,
                                                 unsigned num_items)
 {
        return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
-               3 * num_items;
+               2 * num_items;
 }
 
 /*
@@ -3107,11 +3179,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 +3245,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 +3315,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 +3451,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 +3486,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 +3496,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 +3590,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 +3635,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 +3725,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 +3806,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, ...);
@@ -3828,9 +3930,9 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
                            struct btrfs_root *root);
 int btrfs_recover_relocation(struct btrfs_root *root);
 int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len);
-void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
-                          struct btrfs_root *root, struct extent_buffer *buf,
-                          struct extent_buffer *cow);
+int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root, struct extent_buffer *buf,
+                         struct extent_buffer *cow);
 void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans,
                              struct btrfs_pending_snapshot *pending,
                              u64 *bytes_to_reserve);
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..9efb94e95858e8c53cb84f587b74a064e8701dc4 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) {
@@ -400,7 +400,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
        args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
        btrfs_dev_replace_unlock(dev_replace);
 
-       btrfs_wait_all_ordered_extents(root->fs_info, 0);
+       btrfs_wait_all_ordered_extents(root->fs_info);
 
        /* force writing the updated state information to disk */
        trans = btrfs_start_transaction(root, 0);
@@ -475,7 +475,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
                mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
                return ret;
        }
-       btrfs_wait_all_ordered_extents(root->fs_info, 0);
+       btrfs_wait_all_ordered_extents(root->fs_info);
 
        trans = btrfs_start_transaction(root, 0);
        if (IS_ERR(trans)) {
@@ -535,10 +535,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
        list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list);
 
        btrfs_rm_dev_replace_srcdev(fs_info, src_device);
-       if (src_device->bdev) {
-               /* zero out the old super */
-               btrfs_scratch_superblock(src_device);
-       }
+
        /*
         * this is again a consistent state where no dev_replace procedure
         * is running, the target device is part of the filesystem, the
index 6b092a1c4e37bab47adb0e9fc35ae6ec3e6081f8..62176ad89846173e4d4987da257166fb90b971ff 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"
@@ -156,6 +157,7 @@ static struct btrfs_lockdep_keyset {
        { .id = BTRFS_TREE_LOG_OBJECTID,        .name_stem = "log"      },
        { .id = BTRFS_TREE_RELOC_OBJECTID,      .name_stem = "treloc"   },
        { .id = BTRFS_DATA_RELOC_TREE_OBJECTID, .name_stem = "dreloc"   },
+       { .id = BTRFS_UUID_TREE_OBJECTID,       .name_stem = "uuid"     },
        { .id = 0,                              .name_stem = "tree"     },
 };
 
@@ -302,9 +304,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 +346,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 +496,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 +510,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 +573,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 +610,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 +1145,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 +1292,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 +1379,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 +1412,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 +1427,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 +1528,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;
 
@@ -1562,8 +1561,9 @@ int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
        return ret;
 }
 
-struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
-                                             struct btrfs_key *location)
+struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
+                                    struct btrfs_key *location,
+                                    bool check_ref)
 {
        struct btrfs_root *root;
        int ret;
@@ -1581,16 +1581,22 @@ 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 (check_ref && 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))
                return root;
 
-       if (btrfs_root_refs(&root->root_item) == 0) {
+       if (check_ref && btrfs_root_refs(&root->root_item) == 0) {
                ret = -ENOENT;
                goto fail;
        }
@@ -1737,7 +1743,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 +1755,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 +2045,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 +2111,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 +2205,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 +2287,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 +2296,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 +2402,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 +2472,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 +2485,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 +2591,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 +2631,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 +2711,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 +2913,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 +3037,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 +3367,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 +3375,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);
@@ -3361,9 +3417,12 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
        if (total_errors > max_errors) {
                printk(KERN_ERR "btrfs: %d errors while writing supers\n",
                       total_errors);
+               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
-               /* 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 +3480,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 +3571,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 +3639,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 +3677,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 +3811,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 b71acd6e1e5b1941e75ed4c5c056d47268cdc407..5ce2a7da8b113fef13456687fdf4243fa9f1c2ba 100644 (file)
@@ -68,8 +68,17 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root,
 int btrfs_init_fs_root(struct btrfs_root *root);
 int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
                         struct btrfs_root *root);
-struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
-                                             struct btrfs_key *location);
+
+struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
+                                    struct btrfs_key *key,
+                                    bool check_ref);
+static inline struct btrfs_root *
+btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
+                          struct btrfs_key *location)
+{
+       return btrfs_get_fs_root(fs_info, location, true);
+}
+
 int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info);
 void btrfs_btree_balance_dirty(struct btrfs_root *root);
 void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root);
index 1204c8ef6f32751bd859d2ef1a2ab3444061f708..d58bef130a41984ac7e3172aad43eb87547af64b 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)) {
@@ -3883,7 +3925,6 @@ static int can_overcommit(struct btrfs_root *root,
        u64 space_size;
        u64 avail;
        u64 used;
-       u64 to_add;
 
        used = space_info->bytes_used + space_info->bytes_reserved +
                space_info->bytes_pinned + space_info->bytes_readonly;
@@ -3917,25 +3958,17 @@ static int can_overcommit(struct btrfs_root *root,
                       BTRFS_BLOCK_GROUP_RAID10))
                avail >>= 1;
 
-       to_add = space_info->total_bytes;
-
        /*
         * If we aren't flushing all things, let us overcommit up to
         * 1/2th of the space. If we can flush, don't let us overcommit
         * too much, let it overcommit up to 1/8 of the space.
         */
        if (flush == BTRFS_RESERVE_FLUSH_ALL)
-               to_add >>= 3;
+               avail >>= 3;
        else
-               to_add >>= 1;
-
-       /*
-        * Limit the overcommit to the amount of free space we could possibly
-        * allocate for chunks.
-        */
-       to_add = min(avail, to_add);
+               avail >>= 1;
 
-       if (used + bytes < space_info->total_bytes + to_add)
+       if (used + bytes < space_info->total_bytes + avail)
                return 1;
        return 0;
 }
@@ -3958,7 +3991,7 @@ static void btrfs_writeback_inodes_sb_nr(struct btrfs_root *root,
                 */
                btrfs_start_all_delalloc_inodes(root->fs_info, 0);
                if (!current->journal_info)
-                       btrfs_wait_all_ordered_extents(root->fs_info, 0);
+                       btrfs_wait_all_ordered_extents(root->fs_info);
        }
 }
 
@@ -3988,7 +4021,7 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
        if (delalloc_bytes == 0) {
                if (trans)
                        return;
-               btrfs_wait_all_ordered_extents(root->fs_info, 0);
+               btrfs_wait_all_ordered_extents(root->fs_info);
                return;
        }
 
@@ -4016,7 +4049,7 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
 
                loops++;
                if (wait_ordered && !trans) {
-                       btrfs_wait_all_ordered_extents(root->fs_info, 0);
+                       btrfs_wait_all_ordered_extents(root->fs_info);
                } else {
                        time_left = schedule_timeout_killable(1);
                        if (time_left)
@@ -4320,6 +4353,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;
 
@@ -4420,7 +4456,6 @@ static void block_rsv_release_bytes(struct btrfs_fs_info *fs_info,
                        space_info->bytes_may_use -= num_bytes;
                        trace_btrfs_space_reservation(fs_info, "space_info",
                                        space_info->flags, num_bytes, 0);
-                       space_info->reservation_progress++;
                        spin_unlock(&space_info->lock);
                }
        }
@@ -4621,7 +4656,6 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
                sinfo->bytes_may_use -= num_bytes;
                trace_btrfs_space_reservation(fs_info, "space_info",
                                      sinfo->flags, num_bytes, 0);
-               sinfo->reservation_progress++;
                block_rsv->reserved = block_rsv->size;
                block_rsv->full = 1;
        }
@@ -4729,10 +4763,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 +4787,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);
@@ -5395,7 +5435,6 @@ static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache,
                        space_info->bytes_readonly += num_bytes;
                cache->reserved -= num_bytes;
                space_info->bytes_reserved -= num_bytes;
-               space_info->reservation_progress++;
        }
        spin_unlock(&cache->lock);
        spin_unlock(&space_info->lock);
@@ -5668,7 +5707,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 +5723,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 +5753,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 +6035,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 +6047,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)
@@ -6065,13 +6105,15 @@ enum btrfs_loop_type {
 /*
  * walks the btree of allocated extents and find a hole of a given size.
  * The key ins is changed to record the hole:
- * ins->objectid == block start
+ * ins->objectid == start position
  * ins->flags = BTRFS_EXTENT_ITEM_KEY
- * ins->offset == number of blocks
+ * ins->offset == the size of the hole.
  * Any available blocks before search_start are skipped.
+ *
+ * If there is no suitable free space, we will record the max size of
+ * the free space extent currently.
  */
-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)
@@ -6082,6 +6124,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
        struct btrfs_block_group_cache *block_group = NULL;
        struct btrfs_block_group_cache *used_block_group;
        u64 search_start = 0;
+       u64 max_extent_size = 0;
        int empty_cluster = 2 * 1024 * 1024;
        struct btrfs_space_info *space_info;
        int loop = 0;
@@ -6212,6 +6255,8 @@ have_block_group:
                        ret = 0;
                }
 
+               if (unlikely(block_group->cached == BTRFS_CACHE_ERROR))
+                       goto loop;
                if (unlikely(block_group->ro))
                        goto loop;
 
@@ -6239,7 +6284,10 @@ have_block_group:
                                btrfs_get_block_group(used_block_group);
 
                        offset = btrfs_alloc_from_cluster(used_block_group,
-                         last_ptr, num_bytes, used_block_group->key.objectid);
+                                               last_ptr,
+                                               num_bytes,
+                                               used_block_group->key.objectid,
+                                               &max_extent_size);
                        if (offset) {
                                /* we have a block, we're done */
                                spin_unlock(&last_ptr->refill_lock);
@@ -6292,18 +6340,20 @@ 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
                                 * cluster
                                 */
                                offset = btrfs_alloc_from_cluster(block_group,
-                                                 last_ptr, num_bytes,
-                                                 search_start);
+                                                       last_ptr,
+                                                       num_bytes,
+                                                       search_start,
+                                                       &max_extent_size);
                                if (offset) {
                                        /* we found one, proceed */
                                        spin_unlock(&last_ptr->refill_lock);
@@ -6338,13 +6388,18 @@ unclustered_alloc:
                if (cached &&
                    block_group->free_space_ctl->free_space <
                    num_bytes + empty_cluster + empty_size) {
+                       if (block_group->free_space_ctl->free_space >
+                           max_extent_size)
+                               max_extent_size =
+                                       block_group->free_space_ctl->free_space;
                        spin_unlock(&block_group->free_space_ctl->tree_lock);
                        goto loop;
                }
                spin_unlock(&block_group->free_space_ctl->tree_lock);
 
                offset = btrfs_find_space_for_alloc(block_group, search_start,
-                                                   num_bytes, empty_size);
+                                                   num_bytes, empty_size,
+                                                   &max_extent_size);
                /*
                 * If we didn't find a chunk, and we haven't failed on this
                 * block group before, and this block group is in the middle of
@@ -6426,17 +6481,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) {
@@ -6451,7 +6517,8 @@ loop:
                ret = 0;
        }
 out:
-
+       if (ret == -ENOSPC)
+               ins->offset = max_extent_size;
        return ret;
 }
 
@@ -6463,19 +6530,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 +6549,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 +6560,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,12 +6572,12 @@ 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) {
-                       num_bytes = num_bytes >> 1;
+               if (!final_tried && ins->offset) {
+                       num_bytes = min(num_bytes >> 1, ins->offset);
                        num_bytes = round_down(num_bytes, root->sectorsize);
                        num_bytes = max(num_bytes, min_alloc_size);
                        if (num_bytes == min_alloc_size)
@@ -6529,8 +6588,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 +6608,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 +6704,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 +6776,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 +6958,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 +7229,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 +7716,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 +8250,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 +8468,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..51731b76900de55e8350d5795feacc61a9050d02 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
@@ -150,8 +145,16 @@ int __init extent_io_init(void)
                                     offsetof(struct btrfs_io_bio, bio));
        if (!btrfs_bioset)
                goto free_buffer_cache;
+
+       if (bioset_integrity_create(btrfs_bioset, BIO_POOL_SIZE))
+               goto free_bioset;
+
        return 0;
 
+free_bioset:
+       bioset_free(btrfs_bioset);
+       btrfs_bioset = NULL;
+
 free_buffer_cache:
        kmem_cache_destroy(extent_buffer_cache);
        extent_buffer_cache = NULL;
@@ -388,8 +391,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 +402,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 +763,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.
@@ -1497,11 +1489,11 @@ static noinline u64 find_delalloc_range(struct extent_io_tree *tree,
                *end = state->end;
                cur_start = state->end + 1;
                node = rb_next(node);
-               if (!node)
-                       break;
                total_bytes += state->end - state->start + 1;
                if (total_bytes >= max_bytes)
                        break;
+               if (!node)
+                       break;
        }
 out:
        spin_unlock(&tree->lock);
@@ -1628,7 +1620,7 @@ again:
                *start = delalloc_start;
                *end = delalloc_end;
                free_extent_state(cached_state);
-               return found;
+               return 0;
        }
 
        /*
@@ -1641,10 +1633,9 @@ again:
 
        /*
         * make sure to limit the number of pages we try to lock down
-        * if we're looping.
         */
-       if (delalloc_end + 1 - delalloc_start > max_bytes && loops)
-               delalloc_end = delalloc_start + PAGE_CACHE_SIZE - 1;
+       if (delalloc_end + 1 - delalloc_start > max_bytes)
+               delalloc_end = delalloc_start + max_bytes - 1;
 
        /* step two, lock all the pages after the page that has start */
        ret = lock_delalloc_pages(inode, locked_page,
@@ -1655,8 +1646,7 @@ again:
                 */
                free_extent_state(cached_state);
                if (!loops) {
-                       unsigned long offset = (*start) & (PAGE_CACHE_SIZE - 1);
-                       max_bytes = PAGE_CACHE_SIZE - offset;
+                       max_bytes = PAGE_CACHE_SIZE;
                        loops = 1;
                        goto again;
                } else {
@@ -1687,31 +1677,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 +1700,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 +1790,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 +1817,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 +2095,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 +2124,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 +2136,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 +2221,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 +2263,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 +2275,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 +2375,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 +2403,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 +2419,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 +2439,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 +2475,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 +2501,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 +2542,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 +2558,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 +2575,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 +2709,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 +2761,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 +2807,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 +2826,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 +2870,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 +2881,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 +2900,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 +2915,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 +3027,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 +3297,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 +3876,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 +3893,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 +4241,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 +4359,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 +4388,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 +4409,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 +4879,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 +4921,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 +4949,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 +4983,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 +5013,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 +5044,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 +5130,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 +5183,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..72da4df53c9a224d7a5106a907fc4ba4e08f5ebb 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 {
@@ -1868,8 +1859,8 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 
        ret = btrfs_log_dentry_safe(trans, root, dentry);
        if (ret < 0) {
-               mutex_unlock(&inode->i_mutex);
-               goto out;
+               /* Fallthrough and commit/free transaction. */
+               ret = 1;
        }
 
        /* we've logged all the items and now have a consistent
index b21a3cd667d8cc656878b8d462aa7cd45ebc8435..b4f9904c4c6b2ed5f0da30ad664baf33100a879c 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);
 
@@ -1434,13 +1431,19 @@ static void bitmap_set_bits(struct btrfs_free_space_ctl *ctl,
        ctl->free_space += bytes;
 }
 
+/*
+ * If we can not find suitable extent, we will use bytes to record
+ * the size of the max extent.
+ */
 static int search_bitmap(struct btrfs_free_space_ctl *ctl,
                         struct btrfs_free_space *bitmap_info, u64 *offset,
                         u64 *bytes)
 {
        unsigned long found_bits = 0;
+       unsigned long max_bits = 0;
        unsigned long bits, i;
        unsigned long next_zero;
+       unsigned long extent_bits;
 
        i = offset_to_bit(bitmap_info->offset, ctl->unit,
                          max_t(u64, *offset, bitmap_info->offset));
@@ -1449,9 +1452,12 @@ static int search_bitmap(struct btrfs_free_space_ctl *ctl,
        for_each_set_bit_from(i, bitmap_info->bitmap, BITS_PER_BITMAP) {
                next_zero = find_next_zero_bit(bitmap_info->bitmap,
                                               BITS_PER_BITMAP, i);
-               if ((next_zero - i) >= bits) {
-                       found_bits = next_zero - i;
+               extent_bits = next_zero - i;
+               if (extent_bits >= bits) {
+                       found_bits = extent_bits;
                        break;
+               } else if (extent_bits > max_bits) {
+                       max_bits = extent_bits;
                }
                i = next_zero;
        }
@@ -1462,38 +1468,41 @@ static int search_bitmap(struct btrfs_free_space_ctl *ctl,
                return 0;
        }
 
+       *bytes = (u64)(max_bits) * ctl->unit;
        return -1;
 }
 
+/* Cache the size of the max extent in bytes */
 static struct btrfs_free_space *
 find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes,
-               unsigned long align)
+               unsigned long align, u64 *max_extent_size)
 {
        struct btrfs_free_space *entry;
        struct rb_node *node;
-       u64 ctl_off;
        u64 tmp;
        u64 align_off;
        int ret;
 
        if (!ctl->free_space_offset.rb_node)
-               return NULL;
+               goto out;
 
        entry = tree_search_offset(ctl, offset_to_bitmap(ctl, *offset), 0, 1);
        if (!entry)
-               return NULL;
+               goto out;
 
        for (node = &entry->offset_index; node; node = rb_next(node)) {
                entry = rb_entry(node, struct btrfs_free_space, offset_index);
-               if (entry->bytes < *bytes)
+               if (entry->bytes < *bytes) {
+                       if (entry->bytes > *max_extent_size)
+                               *max_extent_size = entry->bytes;
                        continue;
+               }
 
                /* make sure the space returned is big enough
                 * to match our requested alignment
                 */
                if (*bytes >= align) {
-                       ctl_off = entry->offset - ctl->start;
-                       tmp = ctl_off + align - 1;;
+                       tmp = entry->offset - ctl->start + align - 1;
                        do_div(tmp, align);
                        tmp = tmp * align + ctl->start;
                        align_off = tmp - entry->offset;
@@ -1502,14 +1511,22 @@ find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes,
                        tmp = entry->offset;
                }
 
-               if (entry->bytes < *bytes + align_off)
+               if (entry->bytes < *bytes + align_off) {
+                       if (entry->bytes > *max_extent_size)
+                               *max_extent_size = entry->bytes;
                        continue;
+               }
 
                if (entry->bitmap) {
-                       ret = search_bitmap(ctl, entry, &tmp, bytes);
+                       u64 size = *bytes;
+
+                       ret = search_bitmap(ctl, entry, &tmp, &size);
                        if (!ret) {
                                *offset = tmp;
+                               *bytes = size;
                                return entry;
+                       } else if (size > *max_extent_size) {
+                               *max_extent_size = size;
                        }
                        continue;
                }
@@ -1518,7 +1535,7 @@ find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes,
                *bytes = entry->bytes - align_off;
                return entry;
        }
-
+out:
        return NULL;
 }
 
@@ -1742,7 +1759,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 +1899,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 +2008,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",
@@ -2120,7 +2136,8 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group)
 }
 
 u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
-                              u64 offset, u64 bytes, u64 empty_size)
+                              u64 offset, u64 bytes, u64 empty_size,
+                              u64 *max_extent_size)
 {
        struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *entry = NULL;
@@ -2131,7 +2148,7 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
 
        spin_lock(&ctl->tree_lock);
        entry = find_free_space(ctl, &offset, &bytes_search,
-                               block_group->full_stripe_len);
+                               block_group->full_stripe_len, max_extent_size);
        if (!entry)
                goto out;
 
@@ -2141,7 +2158,6 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
                if (!entry->bytes)
                        free_bitmap(ctl, entry);
        } else {
-
                unlink_free_space(ctl, entry);
                align_gap_len = offset - entry->offset;
                align_gap = entry->offset;
@@ -2155,7 +2171,6 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
                else
                        link_free_space(ctl, entry);
        }
-
 out:
        spin_unlock(&ctl->tree_lock);
 
@@ -2210,7 +2225,8 @@ int btrfs_return_cluster_to_free_space(
 static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group,
                                   struct btrfs_free_cluster *cluster,
                                   struct btrfs_free_space *entry,
-                                  u64 bytes, u64 min_start)
+                                  u64 bytes, u64 min_start,
+                                  u64 *max_extent_size)
 {
        struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        int err;
@@ -2222,8 +2238,11 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group,
        search_bytes = bytes;
 
        err = search_bitmap(ctl, entry, &search_start, &search_bytes);
-       if (err)
+       if (err) {
+               if (search_bytes > *max_extent_size)
+                       *max_extent_size = search_bytes;
                return 0;
+       }
 
        ret = search_start;
        __bitmap_clear_bits(ctl, entry, ret, bytes);
@@ -2238,7 +2257,7 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group,
  */
 u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
                             struct btrfs_free_cluster *cluster, u64 bytes,
-                            u64 min_start)
+                            u64 min_start, u64 *max_extent_size)
 {
        struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *entry = NULL;
@@ -2258,6 +2277,9 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
 
        entry = rb_entry(node, struct btrfs_free_space, offset_index);
        while(1) {
+               if (entry->bytes < bytes && entry->bytes > *max_extent_size)
+                       *max_extent_size = entry->bytes;
+
                if (entry->bytes < bytes ||
                    (!entry->bitmap && entry->offset < min_start)) {
                        node = rb_next(&entry->offset_index);
@@ -2271,7 +2293,8 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
                if (entry->bitmap) {
                        ret = btrfs_alloc_from_bitmap(block_group,
                                                      cluster, entry, bytes,
-                                                     cluster->window_start);
+                                                     cluster->window_start,
+                                                     max_extent_size);
                        if (ret == 0) {
                                node = rb_next(&entry->offset_index);
                                if (!node)
@@ -2371,7 +2394,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 +2487,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 +2548,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 +2878,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 +2995,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;
+       }
 
-       spin_lock_init(&cache->lock);
-       INIT_LIST_HEAD(&cache->list);
-       INIT_LIST_HEAD(&cache->cluster_list);
-       INIT_LIST_HEAD(&cache->new_bg_list);
+       if (!map) {
+               map = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS);
+               if (!map) {
+                       kmem_cache_free(btrfs_free_space_cachep, info);
+                       return -ENOMEM;
+               }
+       }
 
-       btrfs_init_free_space_ctl(cache);
+       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;
+       }
 
-       return cache;
+       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;
 }
 
 /*
@@ -3007,8 +3064,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 +3142,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..e737f92cf6d0b69ffbcc1e94882abc8693c3e3a5 100644 (file)
@@ -94,25 +94,31 @@ void __btrfs_remove_free_space_cache(struct btrfs_free_space_ctl *ctl);
 void btrfs_remove_free_space_cache(struct btrfs_block_group_cache
                                     *block_group);
 u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
-                              u64 offset, u64 bytes, u64 empty_size);
+                              u64 offset, u64 bytes, u64 empty_size,
+                              u64 *max_extent_size);
 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);
 void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster);
 u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
                             struct btrfs_free_cluster *cluster, u64 bytes,
-                            u64 min_start);
+                            u64 min_start, u64 *max_extent_size);
 int btrfs_return_cluster_to_free_space(
                               struct btrfs_block_group_cache *block_group,
                               struct btrfs_free_cluster *cluster);
 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..51e3afa7835479e00fa346241cfccd10b6e60a80 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;
@@ -4725,11 +4688,11 @@ static void inode_tree_add(struct inode *inode)
        struct btrfs_inode *entry;
        struct rb_node **p;
        struct rb_node *parent;
+       struct rb_node *new = &BTRFS_I(inode)->rb_node;
        u64 ino = btrfs_ino(inode);
 
        if (inode_unhashed(inode))
                return;
-again:
        parent = NULL;
        spin_lock(&root->inode_lock);
        p = &root->inode_tree.rb_node;
@@ -4744,14 +4707,14 @@ again:
                else {
                        WARN_ON(!(entry->vfs_inode.i_state &
                                  (I_WILL_FREE | I_FREEING)));
-                       rb_erase(parent, &root->inode_tree);
+                       rb_replace_node(parent, new, &root->inode_tree);
                        RB_CLEAR_NODE(parent);
                        spin_unlock(&root->inode_lock);
-                       goto again;
+                       return;
                }
        }
-       rb_link_node(&BTRFS_I(inode)->rb_node, parent, p);
-       rb_insert_color(&BTRFS_I(inode)->rb_node, &root->inode_tree);
+       rb_link_node(new, parent, p);
+       rb_insert_color(new, &root->inode_tree);
        spin_unlock(&root->inode_lock);
 }
 
@@ -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;
@@ -6484,14 +6437,25 @@ noinline int can_nocow_extent(struct btrfs_trans_handle *trans,
 
        if (btrfs_extent_readonly(root, disk_bytenr))
                goto out;
+       btrfs_release_path(path);
 
        /*
         * 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 +6597,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 +6678,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 +6687,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 +6763,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 +6771,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 +6781,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 +6792,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 +6883,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 +6919,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 +6954,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 +6990,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 +7086,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 +7382,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 +7564,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 +7827,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 +7837,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);
@@ -8037,7 +7987,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 
        /* check for collisions, even if the  name isn't there */
-       ret = btrfs_check_dir_item_collision(root, new_dir->i_ino,
+       ret = btrfs_check_dir_item_collision(dest, new_dir->i_ino,
                             new_dentry->d_name.name,
                             new_dentry->d_name.len);
 
@@ -8161,10 +8111,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;
@@ -8269,6 +8217,10 @@ static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
 
                work = btrfs_alloc_delalloc_work(inode, 0, delay_iput);
                if (unlikely(!work)) {
+                       if (delay_iput)
+                               btrfs_add_delayed_iput(inode);
+                       else
+                               iput(inode);
                        ret = -ENOMEM;
                        goto out;
                }
@@ -8525,8 +8477,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);
@@ -8666,11 +8618,13 @@ static const struct inode_operations btrfs_dir_inode_operations = {
        .removexattr    = btrfs_removexattr,
        .permission     = btrfs_permission,
        .get_acl        = btrfs_get_acl,
+       .update_time    = btrfs_update_time,
 };
 static const struct inode_operations btrfs_dir_ro_inode_operations = {
        .lookup         = btrfs_lookup,
        .permission     = btrfs_permission,
        .get_acl        = btrfs_get_acl,
+       .update_time    = btrfs_update_time,
 };
 
 static const struct file_operations btrfs_dir_file_operations = {
index 238a05545ee2230629fc850191f348b94cadd8cf..9d46f60cb9439ab3a41ab83f2f323f13aa564590 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;
@@ -559,7 +574,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
        if (ret)
                return ret;
 
-       btrfs_wait_ordered_extents(root, 0);
+       btrfs_wait_ordered_extents(root);
 
        pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS);
        if (!pending_snapshot)
@@ -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,350 @@ 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 tmp;
+       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;
+       unsigned long size;
+       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(&tmp,
+                          (struct btrfs_ioctl_same_args __user *)argp,
+                          sizeof(tmp))) {
+               ret = -EFAULT;
+               goto out;
        }
 
-       ret = -EXDEV;
-       if (src_file.file->f_path.mnt != file->f_path.mnt)
-               goto out_fput;
+       size = sizeof(tmp) +
+               tmp.dest_count * sizeof(struct btrfs_ioctl_same_extent_info);
 
-       src = file_inode(src_file.file);
+       same = kmalloc(size, GFP_NOFS);
+       if (!same) {
+               ret = -EFAULT;
+               goto out;
+       }
 
-       ret = -EINVAL;
-       if (src == inode)
-               same_inode = 1;
+       if (copy_from_user(same,
+                          (struct btrfs_ioctl_same_args __user *)argp, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
 
-       /* the src must be open for reading */
-       if (!(src_file.file->f_mode & FMODE_READ))
-               goto out_fput;
+       off = same->logical_offset;
+       len = same->length;
 
-       /* 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;
+       /*
+        * 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 = -EISDIR;
-       if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
-               goto out_fput;
+       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;
+       }
 
-       ret = -EXDEV;
-       if (src->i_sb != inode->i_sb)
-               goto out_fput;
+       ret = -EISDIR;
+       if (S_ISDIR(src->i_mode))
+               goto out;
 
-       ret = -ENOMEM;
-       buf = vmalloc(btrfs_level_size(root, 0));
-       if (!buf)
-               goto out_fput;
+       ret = -EACCES;
+       if (!S_ISREG(src->i_mode))
+               goto out;
 
-       path = btrfs_alloc_path();
-       if (!path) {
-               vfree(buf);
-               goto out_fput;
+       /* pre-format output fields to sane values */
+       for (i = 0; i < same->dest_count; i++) {
+               same->info[i].bytes_deduped = 0ULL;
+               same->info[i].status = 0;
        }
-       path->reada = 2;
 
-       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);
+       ret = 0;
+       for (i = 0; i < same->dest_count; i++) {
+               info = &same->info[i];
+
+               dst_file = fget(info->fd);
+               if (!dst_file) {
+                       info->status = -EBADF;
+                       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 (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) {
+                       info->status = -EINVAL;
+                       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 = -EXDEV;
+               if (file->f_path.mnt != dst_file->f_path.mnt)
+                       goto next;
 
-       /* verify if ranges are overlapped within the same file */
-       if (same_inode) {
-               if (destoff + len > off && destoff < off + len)
-                       goto out_unlock;
-       }
+               dst = dst_file->f_dentry->d_inode;
+               if (src->i_sb != dst->i_sb)
+                       goto next;
 
-       if (destoff > inode->i_size) {
-               ret = btrfs_cont_expand(inode, inode->i_size, destoff);
-               if (ret)
-                       goto out_unlock;
+               if (S_ISDIR(dst->i_mode)) {
+                       info->status = -EISDIR;
+                       goto next;
+               }
+
+               if (!S_ISREG(dst->i_mode)) {
+                       info->status = -EACCES;
+                       goto next;
+               }
+
+               info->status = btrfs_extent_same(src, off, len, dst,
+                                               info->logical_offset);
+               if (info->status == 0)
+                       info->bytes_deduped += len;
+
+next:
+               if (dst_file)
+                       fput(dst_file);
        }
 
-       /* truncate page cache pages from target inode range */
-       truncate_inode_pages_range(&inode->i_data, destoff,
-                                  PAGE_CACHE_ALIGN(destoff + len) - 1);
+       ret = copy_to_user(argp, same, size);
+       if (ret)
+               ret = -EFAULT;
 
-       /* 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);
+out:
+       mnt_drop_write_file(file);
+       return ret;
+}
+
+/**
+ * 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 +3108,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:
@@ -2957,7 +3324,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
        }
 
        if (!objectid)
-               objectid = root->root_key.objectid;
+               objectid = BTRFS_FS_TREE_OBJECTID;
 
        location.objectid = objectid;
        location.type = BTRFS_ROOT_ITEM_KEY;
@@ -3312,11 +3679,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 +3929,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 +4335,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 +4365,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 +4380,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 +4432,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 +4476,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 +4602,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..c702cb62f78a310c8d430fe0d98cfb1173479a0f 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)
@@ -565,11 +563,10 @@ static void btrfs_run_ordered_extent_work(struct btrfs_work *work)
  * wait for all the ordered extents in a root.  This is done when balancing
  * space between drives.
  */
-void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
+void btrfs_wait_ordered_extents(struct btrfs_root *root)
 {
        struct list_head splice, works;
        struct btrfs_ordered_extent *ordered, *next;
-       struct inode *inode;
 
        INIT_LIST_HEAD(&splice);
        INIT_LIST_HEAD(&works);
@@ -582,15 +579,6 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
                                           root_extent_list);
                list_move_tail(&ordered->root_extent_list,
                               &root->ordered_extents);
-               /*
-                * the inode may be getting freed (in sys_unlink path).
-                */
-               inode = igrab(ordered->inode);
-               if (!inode) {
-                       cond_resched_lock(&root->ordered_extent_lock);
-                       continue;
-               }
-
                atomic_inc(&ordered->refs);
                spin_unlock(&root->ordered_extent_lock);
 
@@ -607,21 +595,13 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
        list_for_each_entry_safe(ordered, next, &works, work_list) {
                list_del_init(&ordered->work_list);
                wait_for_completion(&ordered->completion);
-
-               inode = ordered->inode;
                btrfs_put_ordered_extent(ordered);
-               if (delay_iput)
-                       btrfs_add_delayed_iput(inode);
-               else
-                       iput(inode);
-
                cond_resched();
        }
        mutex_unlock(&root->fs_info->ordered_operations_mutex);
 }
 
-void btrfs_wait_all_ordered_extents(struct btrfs_fs_info *fs_info,
-                                   int delay_iput)
+void btrfs_wait_all_ordered_extents(struct btrfs_fs_info *fs_info)
 {
        struct btrfs_root *root;
        struct list_head splice;
@@ -639,7 +619,7 @@ void btrfs_wait_all_ordered_extents(struct btrfs_fs_info *fs_info,
                               &fs_info->ordered_roots);
                spin_unlock(&fs_info->ordered_root_lock);
 
-               btrfs_wait_ordered_extents(root, delay_iput);
+               btrfs_wait_ordered_extents(root);
                btrfs_put_fs_root(root);
 
                spin_lock(&fs_info->ordered_root_lock);
@@ -671,7 +651,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 +698,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 +903,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..0c0b35612d7ad1fc5f5c7db5d267e70f319d8529 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;
 
@@ -188,9 +195,8 @@ int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans,
 void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root,
                                 struct inode *inode);
-void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput);
-void btrfs_wait_all_ordered_extents(struct btrfs_fs_info *fs_info,
-                                   int delay_iput);
+void btrfs_wait_ordered_extents(struct btrfs_root *root);
+void btrfs_wait_all_ordered_extents(struct btrfs_fs_info *fs_info);
 void btrfs_get_logged_extents(struct btrfs_root *log, struct inode *inode);
 void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid);
 void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid);
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..4a355726151ec05dd8e1110745648949888781e8 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);
 }
 
 /*
@@ -588,7 +588,7 @@ static struct btrfs_root *read_fs_root(struct btrfs_fs_info *fs_info,
        else
                key.offset = (u64)-1;
 
-       return btrfs_read_fs_root_no_name(fs_info, &key);
+       return btrfs_get_fs_root(fs_info, &key, false);
 }
 
 #ifdef BTRFS_COMPAT_EXTENT_TREE_V0
@@ -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
@@ -1543,7 +1548,7 @@ static int get_new_location(struct inode *reloc_inode, u64 *new_bytenr,
               btrfs_file_extent_other_encoding(leaf, fi));
 
        if (num_bytes != btrfs_file_extent_disk_num_bytes(leaf, fi)) {
-               ret = 1;
+               ret = -EINVAL;
                goto out;
        }
 
@@ -1574,7 +1579,7 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
        u64 end;
        u32 nritems;
        u32 i;
-       int ret;
+       int ret = 0;
        int first = 1;
        int dirty = 0;
 
@@ -1637,11 +1642,13 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
 
                ret = get_new_location(rc->data_inode, &new_bytenr,
                                       bytenr, num_bytes);
-               if (ret > 0) {
-                       WARN_ON(1);
-                       continue;
+               if (ret) {
+                       /*
+                        * Don't have to abort since we've not changed anything
+                        * in the file extent yet.
+                        */
+                       break;
                }
-               BUG_ON(ret < 0);
 
                btrfs_set_file_extent_disk_bytenr(leaf, fi, new_bytenr);
                dirty = 1;
@@ -1651,18 +1658,24 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
                                           num_bytes, parent,
                                           btrfs_header_owner(leaf),
                                           key.objectid, key.offset, 1);
-               BUG_ON(ret);
+               if (ret) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       break;
+               }
 
                ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
                                        parent, btrfs_header_owner(leaf),
                                        key.objectid, key.offset, 1);
-               BUG_ON(ret);
+               if (ret) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       break;
+               }
        }
        if (dirty)
                btrfs_mark_buffer_dirty(leaf);
        if (inode)
                btrfs_add_delayed_iput(inode);
-       return 0;
+       return ret;
 }
 
 static noinline_for_stack
@@ -2314,8 +2327,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 +2362,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 +3643,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 +3670,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 +3719,7 @@ int add_data_references(struct reloc_control *rc,
                }
                path->slots[0]++;
        }
+out:
        btrfs_release_path(path);
        if (err)
                free_block_list(blocks);
@@ -4219,15 +4239,14 @@ 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) {
                err = ret;
                goto out;
        }
-       btrfs_wait_all_ordered_extents(fs_info, 0);
+       btrfs_wait_all_ordered_extents(fs_info);
 
        while (1) {
                mutex_lock(&fs_info->cleaner_mutex);
@@ -4242,7 +4261,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);
@@ -4488,19 +4507,19 @@ out:
        return ret;
 }
 
-void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
-                          struct btrfs_root *root, struct extent_buffer *buf,
-                          struct extent_buffer *cow)
+int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root, struct extent_buffer *buf,
+                         struct extent_buffer *cow)
 {
        struct reloc_control *rc;
        struct backref_node *node;
        int first_cow = 0;
        int level;
-       int ret;
+       int ret = 0;
 
        rc = root->fs_info->reloc_ctl;
        if (!rc)
-               return;
+               return 0;
 
        BUG_ON(rc->stage == UPDATE_DATA_PTRS &&
               root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID);
@@ -4536,10 +4555,9 @@ void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
                        rc->nodes_relocated += buf->len;
        }
 
-       if (level == 0 && first_cow && rc->stage == UPDATE_DATA_PTRS) {
+       if (level == 0 && first_cow && rc->stage == UPDATE_DATA_PTRS)
                ret = replace_file_extents(trans, rc, root, cow);
-               BUG_ON(ret);
-       }
+       return ret;
 }
 
 /*
index ffb1036ef10db97f31bfa4c00ca7c36a45d09e4f..ec71ea44d2b4626c9a2bcc73b5fb94af666eaf5b 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);
        }
 
@@ -300,11 +299,6 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
                        continue;
                }
 
-               if (btrfs_root_refs(&root->root_item) == 0) {
-                       btrfs_add_dead_root(root);
-                       continue;
-               }
-
                err = btrfs_init_fs_root(root);
                if (err) {
                        btrfs_free_fs_root(root);
@@ -319,6 +313,9 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
                        btrfs_free_fs_root(root);
                        break;
                }
+
+               if (btrfs_root_refs(&root->root_item) == 0)
+                       btrfs_add_dead_root(root);
        }
 
        btrfs_free_path(path);
@@ -490,13 +487,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 +504,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..a18e0e23f6a6742cd21277702ed6599df84c32c3 100644 (file)
@@ -158,12 +158,20 @@ struct scrub_fixup_nodatasum {
        int                     mirror_num;
 };
 
+struct scrub_nocow_inode {
+       u64                     inum;
+       u64                     offset;
+       u64                     root;
+       struct list_head        list;
+};
+
 struct scrub_copy_nocow_ctx {
        struct scrub_ctx        *sctx;
        u64                     logical;
        u64                     len;
        int                     mirror_num;
        u64                     physical_for_dev_replace;
+       struct list_head        inodes;
        struct btrfs_work       work;
 };
 
@@ -245,7 +253,7 @@ static void scrub_wr_bio_end_io_worker(struct btrfs_work *work);
 static int write_page_nocow(struct scrub_ctx *sctx,
                            u64 physical_for_dev_replace, struct page *page);
 static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root,
-                                     void *ctx);
+                                     struct scrub_copy_nocow_ctx *ctx);
 static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
                            int mirror_num, u64 physical_for_dev_replace);
 static void copy_nocow_pages_worker(struct btrfs_work *work);
@@ -754,8 +762,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 +1161,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 +1170,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 +1350,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 +1725,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 +1791,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 +2460,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 +2867,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;
        }
 
@@ -3131,12 +3134,30 @@ static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
        nocow_ctx->mirror_num = mirror_num;
        nocow_ctx->physical_for_dev_replace = physical_for_dev_replace;
        nocow_ctx->work.func = copy_nocow_pages_worker;
+       INIT_LIST_HEAD(&nocow_ctx->inodes);
        btrfs_queue_worker(&fs_info->scrub_nocow_workers,
                           &nocow_ctx->work);
 
        return 0;
 }
 
+static int record_inode_for_nocow(u64 inum, u64 offset, u64 root, void *ctx)
+{
+       struct scrub_copy_nocow_ctx *nocow_ctx = ctx;
+       struct scrub_nocow_inode *nocow_inode;
+
+       nocow_inode = kzalloc(sizeof(*nocow_inode), GFP_NOFS);
+       if (!nocow_inode)
+               return -ENOMEM;
+       nocow_inode->inum = inum;
+       nocow_inode->offset = offset;
+       nocow_inode->root = root;
+       list_add_tail(&nocow_inode->list, &nocow_ctx->inodes);
+       return 0;
+}
+
+#define COPY_COMPLETE 1
+
 static void copy_nocow_pages_worker(struct btrfs_work *work)
 {
        struct scrub_copy_nocow_ctx *nocow_ctx =
@@ -3172,19 +3193,42 @@ static void copy_nocow_pages_worker(struct btrfs_work *work)
        }
 
        ret = iterate_inodes_from_logical(logical, fs_info, path,
-                                         copy_nocow_pages_for_inode,
-                                         nocow_ctx);
+                                         record_inode_for_nocow, 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;
        }
 
+       btrfs_end_transaction(trans, root);
+       trans = NULL;
+       while (!list_empty(&nocow_ctx->inodes)) {
+               struct scrub_nocow_inode *entry;
+               entry = list_first_entry(&nocow_ctx->inodes,
+                                        struct scrub_nocow_inode,
+                                        list);
+               list_del_init(&entry->list);
+               ret = copy_nocow_pages_for_inode(entry->inum, entry->offset,
+                                                entry->root, nocow_ctx);
+               kfree(entry);
+               if (ret == COPY_COMPLETE) {
+                       ret = 0;
+                       break;
+               } else if (ret) {
+                       break;
+               }
+       }
 out:
+       while (!list_empty(&nocow_ctx->inodes)) {
+               struct scrub_nocow_inode *entry;
+               entry = list_first_entry(&nocow_ctx->inodes,
+                                        struct scrub_nocow_inode,
+                                        list);
+               list_del_init(&entry->list);
+               kfree(entry);
+       }
        if (trans && !IS_ERR(trans))
                btrfs_end_transaction(trans, root);
        if (not_written)
@@ -3197,20 +3241,25 @@ out:
        scrub_pending_trans_workers_dec(sctx);
 }
 
-static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx)
+static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root,
+                                     struct scrub_copy_nocow_ctx *nocow_ctx)
 {
-       struct scrub_copy_nocow_ctx *nocow_ctx = ctx;
        struct btrfs_fs_info *fs_info = nocow_ctx->sctx->dev_root->fs_info;
        struct btrfs_key key;
        struct inode *inode;
        struct page *page;
        struct btrfs_root *local_root;
+       struct btrfs_ordered_extent *ordered;
+       struct extent_map *em;
+       struct extent_state *cached_state = NULL;
+       struct extent_io_tree *io_tree;
        u64 physical_for_dev_replace;
-       u64 len;
+       u64 len = nocow_ctx->len;
+       u64 lockstart = offset, lockend = offset + len - 1;
        unsigned long index;
        int srcu_index;
-       int ret;
-       int err;
+       int ret = 0;
+       int err = 0;
 
        key.objectid = root;
        key.type = BTRFS_ROOT_ITEM_KEY;
@@ -3224,11 +3273,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;
@@ -3241,9 +3285,33 @@ static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx)
        mutex_lock(&inode->i_mutex);
        inode_dio_wait(inode);
 
-       ret = 0;
        physical_for_dev_replace = nocow_ctx->physical_for_dev_replace;
-       len = nocow_ctx->len;
+       io_tree = &BTRFS_I(inode)->io_tree;
+
+       lock_extent_bits(io_tree, lockstart, lockend, 0, &cached_state);
+       ordered = btrfs_lookup_ordered_range(inode, lockstart, len);
+       if (ordered) {
+               btrfs_put_ordered_extent(ordered);
+               goto out_unlock;
+       }
+
+       em = btrfs_get_extent(inode, NULL, 0, lockstart, len, 0);
+       if (IS_ERR(em)) {
+               ret = PTR_ERR(em);
+               goto out_unlock;
+       }
+
+       /*
+        * This extent does not actually cover the logical extent anymore,
+        * move on to the next inode.
+        */
+       if (em->block_start > nocow_ctx->logical ||
+           em->block_start + em->block_len < nocow_ctx->logical + len) {
+               free_extent_map(em);
+               goto out_unlock;
+       }
+       free_extent_map(em);
+
        while (len >= PAGE_CACHE_SIZE) {
                index = offset >> PAGE_CACHE_SHIFT;
 again:
@@ -3259,10 +3327,9 @@ again:
                                goto next_page;
                } else {
                        ClearPageError(page);
-                       err = extent_read_full_page(&BTRFS_I(inode)->
-                                                        io_tree,
-                                                       page, btrfs_get_extent,
-                                                       nocow_ctx->mirror_num);
+                       err = extent_read_full_page_nolock(io_tree, page,
+                                                          btrfs_get_extent,
+                                                          nocow_ctx->mirror_num);
                        if (err) {
                                ret = err;
                                goto next_page;
@@ -3276,6 +3343,7 @@ again:
                         * page in the page cache.
                         */
                        if (page->mapping != inode->i_mapping) {
+                               unlock_page(page);
                                page_cache_release(page);
                                goto again;
                        }
@@ -3299,6 +3367,10 @@ next_page:
                physical_for_dev_replace += PAGE_CACHE_SIZE;
                len -= PAGE_CACHE_SIZE;
        }
+       ret = COPY_COMPLETE;
+out_unlock:
+       unlock_extent_cached(io_tree, lockstart, lockend, &cached_state,
+                            GFP_NOFS);
 out:
        mutex_unlock(&inode->i_mutex);
        iput(inode);
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..e913328d0f2adc9c3beb2c37556a479c7615d2fa 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:
@@ -865,7 +921,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
                return 0;
        }
 
-       btrfs_wait_all_ordered_extents(fs_info, 1);
+       btrfs_wait_all_ordered_extents(fs_info);
 
        trans = btrfs_attach_transaction_barrier(root);
        if (IS_ERR(trans)) {
@@ -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;
 }
 
@@ -1268,6 +1340,12 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                if (ret)
                        goto restore;
        } else {
+               if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) {
+                       btrfs_err(fs_info,
+                               "Remounting read-write after error is not allowed\n");
+                       ret = -EINVAL;
+                       goto restore;
+               }
                if (fs_info->fs_devices->rw_devices == 0) {
                        ret = -EACCES;
                        goto restore;
@@ -1305,6 +1383,16 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                        pr_warn("btrfs: failed to resume dev_replace\n");
                        goto restore;
                }
+
+               if (!fs_info->uuid_root) {
+                       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);
+                               goto restore;
+                       }
+               }
                sb->s_flags &= ~MS_RDONLY;
        }
 out:
@@ -1690,12 +1778,20 @@ static void btrfs_print_info(void)
 #ifdef CONFIG_BTRFS_DEBUG
                        ", debug=on"
 #endif
+#ifdef CONFIG_BTRFS_ASSERT
+                       ", assert=on"
+#endif
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
                        ", integrity-checker=on"
 #endif
                        "\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 +1830,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 +1882,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..8c81bdc1ef9bae82c92e5a8836a0f911c1547a55 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)
@@ -1583,7 +1603,7 @@ static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
 static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
 {
        if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
-               btrfs_wait_all_ordered_extents(fs_info, 1);
+               btrfs_wait_all_ordered_extents(fs_info);
 }
 
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
@@ -1818,11 +1838,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        assert_qgroups_uptodate(trans);
        update_super_roots(root);
 
-       if (!root->fs_info->log_root_recovering) {
-               btrfs_set_super_log_root(root->fs_info->super_copy, 0);
-               btrfs_set_super_log_root_level(root->fs_info->super_copy, 0);
-       }
-
+       btrfs_set_super_log_root(root->fs_info->super_copy, 0);
+       btrfs_set_super_log_root_level(root->fs_info->super_copy, 0);
        memcpy(root->fs_info->super_for_commit, root->fs_info->super_copy,
               sizeof(*root->fs_info->super_copy));
 
@@ -1928,8 +1945,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 +1958,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..79f057c0619a5cfe29a6e47dcd3ebeccebce9809 100644 (file)
@@ -93,7 +93,8 @@
  */
 #define LOG_WALK_PIN_ONLY 0
 #define LOG_WALK_REPLAY_INODES 1
-#define LOG_WALK_REPLAY_ALL 2
+#define LOG_WALK_REPLAY_DIR_INDEX 2
+#define LOG_WALK_REPLAY_ALL 3
 
 static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root, struct inode *inode,
@@ -393,6 +394,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
                if (inode_item) {
                        struct btrfs_inode_item *item;
                        u64 nbytes;
+                       u32 mode;
 
                        item = btrfs_item_ptr(path->nodes[0], path->slots[0],
                                              struct btrfs_inode_item);
@@ -400,9 +402,19 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
                        item = btrfs_item_ptr(eb, slot,
                                              struct btrfs_inode_item);
                        btrfs_set_inode_nbytes(eb, item, nbytes);
+
+                       /*
+                        * If this is a directory we need to reset the i_size to
+                        * 0 so that we can set it up properly when replaying
+                        * the rest of the items in this log.
+                        */
+                       mode = btrfs_inode_mode(eb, item);
+                       if (S_ISDIR(mode))
+                               btrfs_set_inode_size(eb, item, 0);
                }
        } else if (inode_item) {
                struct btrfs_inode_item *item;
+               u32 mode;
 
                /*
                 * New inode, set nbytes to 0 so that the nbytes comes out
@@ -410,6 +422,15 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
                 */
                item = btrfs_item_ptr(eb, slot, struct btrfs_inode_item);
                btrfs_set_inode_nbytes(eb, item, 0);
+
+               /*
+                * If this is a directory we need to reset the i_size to 0 so
+                * that we can set it up properly when replaying the rest of
+                * the items in this log.
+                */
+               mode = btrfs_inode_mode(eb, item);
+               if (S_ISDIR(mode))
+                       btrfs_set_inode_size(eb, item, 0);
        }
 insert:
        btrfs_release_path(path);
@@ -747,7 +768,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 +945,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 +1014,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);
@@ -1491,6 +1517,7 @@ static noinline int insert_one_name(struct btrfs_trans_handle *trans,
                iput(inode);
                return -EIO;
        }
+
        ret = btrfs_add_link(trans, dir, inode, name, name_len, 1, index);
 
        /* FIXME, put inode into FIXUP list */
@@ -1529,6 +1556,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
        u8 log_type;
        int exists;
        int ret = 0;
+       bool update_size = (key->type == BTRFS_DIR_INDEX_KEY);
 
        dir = read_one_inode(root, key->objectid);
        if (!dir)
@@ -1536,8 +1564,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),
@@ -1597,6 +1627,10 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
                goto insert;
 out:
        btrfs_release_path(path);
+       if (!ret && update_size) {
+               btrfs_i_size_write(dir, dir->i_size + name_len * 2);
+               ret = btrfs_update_inode(trans, root, dir);
+       }
        kfree(name);
        iput(dir);
        return ret;
@@ -1607,6 +1641,7 @@ insert:
                              name, name_len, log_type, &log_key);
        if (ret && ret != -ENOENT)
                goto out;
+       update_size = false;
        ret = 0;
        goto out;
 }
@@ -1810,7 +1845,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)
@@ -2020,6 +2055,15 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
                        if (ret)
                                break;
                }
+
+               if (key.type == BTRFS_DIR_INDEX_KEY &&
+                   wc->stage == LOG_WALK_REPLAY_DIR_INDEX) {
+                       ret = replay_one_dir_item(wc->trans, root, path,
+                                                 eb, i, &key);
+                       if (ret)
+                               break;
+               }
+
                if (wc->stage < LOG_WALK_REPLAY_ALL)
                        continue;
 
@@ -2041,8 +2085,7 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
                                                eb, i, &key);
                        if (ret)
                                break;
-               } else if (key.type == BTRFS_DIR_ITEM_KEY ||
-                          key.type == BTRFS_DIR_INDEX_KEY) {
+               } else if (key.type == BTRFS_DIR_ITEM_KEY) {
                        ret = replay_one_dir_item(wc->trans, root, path,
                                                  eb, i, &key);
                        if (ret)
@@ -3798,6 +3841,7 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
        int ret = 0;
        struct btrfs_root *root;
        struct dentry *old_parent = NULL;
+       struct inode *orig_inode = inode;
 
        /*
         * for regular files, if its inode is already on disk, we don't
@@ -3817,7 +3861,14 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
        }
 
        while (1) {
-               BTRFS_I(inode)->logged_trans = trans->transid;
+               /*
+                * If we are logging a directory then we start with our inode,
+                * not our parents inode, so we need to skipp setting the
+                * logged_trans so that further down in the log code we don't
+                * think this inode has already been logged.
+                */
+               if (inode != orig_inode)
+                       BTRFS_I(inode)->logged_trans = trans->transid;
                smp_mb();
 
                if (BTRFS_I(inode)->last_unlink_trans > last_committed) {
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..043b215769c2c68c538ea147d5cde0721221b833 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);
        }
@@ -760,7 +796,8 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                        fs_devices->rotating = 1;
 
                fs_devices->open_devices++;
-               if (device->writeable && !device->is_tgtdev_for_dev_replace) {
+               if (device->writeable &&
+                   device->devid != BTRFS_DEV_REPLACE_DEVID) {
                        fs_devices->rw_devices++;
                        list_add(&device->dev_alloc_list,
                                 &fs_devices->alloc_list);
@@ -865,7 +902,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);
@@ -875,13 +912,12 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
        if (disk_super->label[0]) {
                if (disk_super->label[BTRFS_LABEL_SIZE - 1])
                        disk_super->label[BTRFS_LABEL_SIZE - 1] = '\0';
-               printk(KERN_INFO "device label %s ", disk_super->label);
+               printk(KERN_INFO "btrfs: device label %s ", disk_super->label);
        } else {
-               printk(KERN_INFO "device fsid %pU ", disk_super->fsid);
+               printk(KERN_INFO "btrfs: 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 +1314,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 +1342,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 +1358,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 +1426,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 +1597,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 +1623,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 +1651,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;
@@ -1675,6 +1716,7 @@ void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info,
                                 struct btrfs_device *srcdev)
 {
        WARN_ON(!mutex_is_locked(&fs_info->fs_devices->device_list_mutex));
+
        list_del_rcu(&srcdev->dev_list);
        list_del_rcu(&srcdev->dev_alloc_list);
        fs_info->fs_devices->num_devices--;
@@ -1684,9 +1726,13 @@ void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info,
        }
        if (srcdev->can_discard)
                fs_info->fs_devices->num_can_discard--;
-       if (srcdev->bdev)
+       if (srcdev->bdev) {
                fs_info->fs_devices->open_devices--;
 
+               /* zero out the old super */
+               btrfs_scratch_superblock(srcdev);
+       }
+
        call_rcu(&srcdev->rcu, free_device);
 }
 
@@ -1793,9 +1839,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 +1860,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 +1875,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 +1936,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 +2001,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 +2016,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 +2030,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 +2156,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 +2178,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 +2197,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 +3003,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 +3038,8 @@ again:
                        spin_unlock(&fs_info->balance_lock);
                }
 loop:
+               if (found_key.offset == 0)
+                       break;
                key.offset = found_key.offset - 1;
        }
 
@@ -3074,9 +3104,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 +3166,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 +3175,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 +3184,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 +3457,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 +4479,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 +4660,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 +4955,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 +5531,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 +5597,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 +5769,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 +5832,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 +5849,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 +5973,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 +5997,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 +6013,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 4d7433534f5cd77b7f9b240fba57ac7923df07e6..6024877335caf2a9dfa6af1018c5da19b0e8a2ae 100644 (file)
@@ -1005,9 +1005,19 @@ grow_dev_page(struct block_device *bdev, sector_t block,
        struct buffer_head *bh;
        sector_t end_block;
        int ret = 0;            /* Will call free_more_memory() */
+       gfp_t gfp_mask;
 
-       page = find_or_create_page(inode->i_mapping, index,
-               (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE);
+       gfp_mask = mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS;
+       gfp_mask |= __GFP_MOVABLE;
+       /*
+        * XXX: __getblk_slow() can not really deal with failure and
+        * will endlessly loop on improvised global reclaim.  Prefer
+        * looping in the allocator rather than here, at least that
+        * code knows what it's doing.
+        */
+       gfp_mask |= __GFP_NOFAIL;
+
+       page = find_or_create_page(inode->i_mapping, index, gfp_mask);
        if (!page)
                return ret;
 
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 25badd1aec5c677215f20d9bd970261deab2dd35..f4a08d7fa2f70a58a8513110988cc4928a674bdb 100644 (file)
@@ -56,7 +56,7 @@ void __cachefiles_printk_object(struct cachefiles_object *object,
                       object->fscache.cookie->parent,
                       object->fscache.cookie->netfs_data,
                       object->fscache.cookie->flags);
-               if (keybuf)
+               if (keybuf && cookie->def)
                        keylen = cookie->def->get_key(cookie->netfs_data, keybuf,
                                                      CACHEFILES_KEYBUF_SIZE);
                else
index 2476e5162609ffc4db6be49549e27999e288f06f..12b0eef84183be5edb35627b169cbe49a516a961 100644 (file)
@@ -156,6 +156,43 @@ 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;
+       enum fscache_checkaux validity;
+       struct dentry *dentry = object->dentry;
+       ssize_t xlen;
+       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;
+
+       xlen = vfs_getxattr(dentry, cachefiles_xattr_cache,
+                           &auxbuf->type, 512 + 1);
+       ret = -ESTALE;
+       if (xlen < 1 ||
+           auxbuf->type != object->fscache.cookie->def->type)
+               goto error;
+
+       xlen--;
+       validity = fscache_check_aux(&object->fscache, &auxbuf->data, xlen);
+       if (validity != FSCACHE_CHECKAUX_OKAY)
+               goto error;
+
+       ret = 0;
+error:
+       kfree(auxbuf);
+       return ret;
+}
+
 /*
  * 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 */
 };
 
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
 
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..77fc5e181077b1f897cf27d40c140133b6cf6d0f 100644 (file)
@@ -120,14 +120,16 @@ cifs_read_super(struct super_block *sb)
 {
        struct inode *inode;
        struct cifs_sb_info *cifs_sb;
+       struct cifs_tcon *tcon;
        int rc = 0;
 
        cifs_sb = CIFS_SB(sb);
+       tcon = cifs_sb_master_tcon(cifs_sb);
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL)
                sb->s_flags |= MS_POSIXACL;
 
-       if (cifs_sb_master_tcon(cifs_sb)->ses->capabilities & CAP_LARGE_FILES)
+       if (tcon->ses->capabilities & tcon->ses->server->vals->cap_large_files)
                sb->s_maxbytes = MAX_LFS_FILESIZE;
        else
                sb->s_maxbytes = MAX_NON_LFS;
@@ -147,7 +149,7 @@ cifs_read_super(struct super_block *sb)
                goto out_no_root;
        }
 
-       if (cifs_sb_master_tcon(cifs_sb)->nocase)
+       if (tcon->nocase)
                sb->s_d_op = &cifs_ci_dentry_ops;
        else
                sb->s_d_op = &cifs_dentry_ops;
@@ -255,6 +257,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 +360,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 +433,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 +736,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 +761,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 +785,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 +796,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 ea723a5e8226231d64cd85eab065c7f91801a3a0..6d0b07217ac9a6ec5b2887125fdb3fa60800642c 100644 (file)
@@ -132,5 +132,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* CONFIG_CIFS_NFSD_EXPORT */
 
-#define CIFS_VERSION   "2.01"
+#define CIFS_VERSION   "2.02"
 #endif                         /* _CIFSFS_H */
index 52ca861ed35e4fe3fbf78ec387ff401fb0e8fb94..52b6f6c26bfcbe37d2994ba0fe3fa0b3779016d4 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)
@@ -541,14 +547,10 @@ struct TCP_Server_Info {
        unsigned int max_rw;    /* maxRw specifies the maximum */
        /* message size the server can send or receive for */
        /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
-       unsigned int max_vcs;   /* maximum number of smb sessions, at least
-                                  those that can be specified uniquely with
-                                  vcnumbers */
        unsigned int capabilities; /* selective disabling of caps by smb sess */
        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 */
@@ -710,7 +712,6 @@ struct cifs_ses {
        enum statusEnum status;
        unsigned overrideSecFlg;  /* if non-zero override global sec flags */
        __u16 ipc_tid;          /* special tid for connection to IPC share */
-       __u16 vcnum;
        char *serverOS;         /* name of operating system underlying server */
        char *serverNOS;        /* name of network operating system of server */
        char *serverDomain;     /* security realm of server */
@@ -731,6 +732,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 +937,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 +1036,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 +1058,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 */
@@ -1253,6 +1268,7 @@ struct dfs_info3_param {
 #define CIFS_FATTR_DELETE_PENDING      0x2
 #define CIFS_FATTR_NEED_REVAL          0x4
 #define CIFS_FATTR_INO_COLLISION       0x8
+#define CIFS_FATTR_UNKNOWN_NLINK       0x10
 
 struct cifs_fattr {
        u32             cf_flags;
@@ -1502,7 +1518,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..08f9dfb1a894402eec24579717f6c48d4d92f695 100644 (file)
@@ -1491,15 +1491,31 @@ struct file_notify_information {
        __u8  FileName[0];
 } __attribute__((packed));
 
-struct reparse_data {
-       __u32   ReparseTag;
-       __u16   ReparseDataLength;
+/* For IO_REPARSE_TAG_SYMLINK */
+struct reparse_symlink_data {
+       __le32  ReparseTag;
+       __le16  ReparseDataLength;
        __u16   Reserved;
-       __u16   AltNameOffset;
-       __u16   AltNameLen;
-       __u16   TargetNameOffset;
-       __u16   TargetNameLen;
-       char    LinkNamesBuf[1];
+       __le16  SubstituteNameOffset;
+       __le16  SubstituteNameLength;
+       __le16  PrintNameOffset;
+       __le16  PrintNameLength;
+       __le32  Flags;
+       char    PathBuffer[0];
+} __attribute__((packed));
+
+/* For IO_REPARSE_TAG_NFS */
+#define NFS_SPECFILE_LNK       0x00000000014B4E4C
+#define NFS_SPECFILE_CHR       0x0000000000524843
+#define NFS_SPECFILE_BLK       0x00000000004B4C42
+#define NFS_SPECFILE_FIFO      0x000000004F464946
+#define NFS_SPECFILE_SOCK      0x000000004B434F53
+struct reparse_posix_data {
+       __le32  ReparseTag;
+       __le16  ReparseDataLength;
+       __u16   Reserved;
+       __le64  InodeType; /* LNK, FIFO, CHR etc. */
+       char    PathBuffer[0];
 } __attribute__((packed));
 
 struct cifs_quota_data {
@@ -2651,26 +2667,7 @@ typedef struct file_xattr_info {
 } __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute info
                                              level 0x205 */
 
-
-/* flags for chattr command */
-#define EXT_SECURE_DELETE              0x00000001 /* EXT3_SECRM_FL */
-#define EXT_ENABLE_UNDELETE            0x00000002 /* EXT3_UNRM_FL */
-/* Reserved for compress file 0x4 */
-#define EXT_SYNCHRONOUS                        0x00000008 /* EXT3_SYNC_FL */
-#define EXT_IMMUTABLE_FL               0x00000010 /* EXT3_IMMUTABLE_FL */
-#define EXT_OPEN_APPEND_ONLY           0x00000020 /* EXT3_APPEND_FL */
-#define EXT_DO_NOT_BACKUP              0x00000040 /* EXT3_NODUMP_FL */
-#define EXT_NO_UPDATE_ATIME            0x00000080 /* EXT3_NOATIME_FL */
-/* 0x100 through 0x800 reserved for compression flags and are GET-ONLY */
-#define EXT_HASH_TREE_INDEXED_DIR      0x00001000 /* GET-ONLY EXT3_INDEX_FL */
-/* 0x2000 reserved for IMAGIC_FL */
-#define EXT_JOURNAL_THIS_FILE  0x00004000 /* GET-ONLY EXT3_JOURNAL_DATA_FL */
-/* 0x8000 reserved for EXT3_NOTAIL_FL */
-#define EXT_SYNCHRONOUS_DIR            0x00010000 /* EXT3_DIRSYNC_FL */
-#define EXT_TOPDIR                     0x00020000 /* EXT3_TOPDIR_FL */
-
-#define EXT_SET_MASK                   0x000300FF
-#define EXT_GET_MASK                   0x0003DFFF
+/* flags for lsattr and chflags commands removed arein uapi/linux/fs.h */
 
 typedef struct file_chattr_info {
        __le64  mask; /* list of all possible attribute bits */
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..ccd31ab815d4b2404d58a0e42f3ad606d35b87f5 100644 (file)
@@ -463,7 +463,6 @@ decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
                               cifs_max_pending);
        set_credits(server, server->maxReq);
        server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
-       server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
        /* even though we do not use raw we might as well set this
        accurately, in case we ever find a need for it */
        if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
@@ -3067,7 +3066,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 +3077,23 @@ 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_symlink_data *reparse_buf;
+       struct reparse_posix_data *posix_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,82 @@ 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;
+       }
+
+       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_symlink_data *)
+                               ((char *)&pSMBr->hdr.Protocol + data_offset);
+       if ((char *)reparse_buf >= end_of_smb) {
+               rc = -EIO;
+               goto qreparse_out;
+       }
+       if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
+               cifs_dbg(FYI, "NFS style reparse tag\n");
+               posix_buf =  (struct reparse_posix_data *)reparse_buf;
+
+               if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
+                       cifs_dbg(FYI, "unsupported file type 0x%llx\n",
+                                le64_to_cpu(posix_buf->InodeType));
+                       rc = -EOPNOTSUPP;
                        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;
-                       }
-
-                       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 {
+               is_unicode = true;
+               sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
+               if (posix_buf->PathBuffer + sub_len > end_of_smb) {
+                       cifs_dbg(FYI, "reparse buf beyond SMB\n");
                        rc = -EIO;
-                       cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
+                       goto qreparse_out;
                }
-               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);
+               *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
+                               sub_len, is_unicode, nls_codepage);
+               goto qreparse_out;
+       } else if (reparse_buf->ReparseTag !=
+                       cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
+               rc = -EOPNOTSUPP;
+               goto qreparse_out;
+       }
+
+       /* Reparse tag is NTFS symlink */
+       sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
+                               reparse_buf->PathBuffer;
+       sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
+       if (sub_start + sub_len > end_of_smb) {
+               cifs_dbg(FYI, "reparse buf beyond SMB\n");
+               rc = -EIO;
+               goto qreparse_out;
        }
+       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..7ddddf2e25046af5fceb6fcbe097e2b14750710c 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;
@@ -3251,6 +3254,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
        /*
         * Reads as many pages as possible from fscache. Returns -ENOBUFS
         * immediately if the cookie is negative
+        *
+        * After this point, every page in the list might have PG_fscache set,
+        * so we will need to clean that up off of every page we don't use.
         */
        rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
                                         &num_pages);
@@ -3373,9 +3379,17 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                kref_put(&rdata->refcount, cifs_readdata_release);
        }
 
+       /* Any pages that have been shown to fscache but didn't get added to
+        * the pagecache must be uncached before they get returned to the
+        * allocator.
+        */
+       cifs_fscache_readpages_cancel(mapping->host, page_list);
        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 +3401,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 +3427,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 +3452,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 +3505,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 +3515,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 +3539,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 +3557,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 +3625,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 2f4bc5a58054e65475b675c4e591a72bbfb706b0..b3258f35e88a5126d61b463bb4d96387e5dcba42 100644 (file)
@@ -223,6 +223,13 @@ void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
                fscache_uncache_page(CIFS_I(inode)->fscache, page);
 }
 
+void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages)
+{
+       cifs_dbg(FYI, "%s: (fsc: %p, i: %p)\n",
+                __func__, CIFS_I(inode)->fscache, inode);
+       fscache_readpages_cancel(CIFS_I(inode)->fscache, pages);
+}
+
 void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
 {
        struct cifsInodeInfo *cifsi = CIFS_I(inode);
index 63539323e0b960f3ecf9788eca6e67ba0ec8ce67..24794b6cd8ec5d18ce9248a6469315a1d8eebf08 100644 (file)
@@ -54,6 +54,7 @@ extern int __cifs_readpages_from_fscache(struct inode *,
                                         struct address_space *,
                                         struct list_head *,
                                         unsigned *);
+extern void __cifs_fscache_readpages_cancel(struct inode *, struct list_head *);
 
 extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
 
@@ -91,6 +92,13 @@ static inline void cifs_readpage_to_fscache(struct inode *inode,
                __cifs_readpage_to_fscache(inode, page);
 }
 
+static inline void cifs_fscache_readpages_cancel(struct inode *inode,
+                                                struct list_head *pages)
+{
+       if (CIFS_I(inode)->fscache)
+               return __cifs_fscache_readpages_cancel(inode, pages);
+}
+
 #else /* CONFIG_CIFS_FSCACHE */
 static inline int cifs_fscache_register(void) { return 0; }
 static inline void cifs_fscache_unregister(void) {}
@@ -131,6 +139,11 @@ static inline int cifs_readpages_from_fscache(struct inode *inode,
 static inline void cifs_readpage_to_fscache(struct inode *inode,
                        struct page *page) {}
 
+static inline void cifs_fscache_readpages_cancel(struct inode *inode,
+                                                struct list_head *pages)
+{
+}
+
 #endif /* CONFIG_CIFS_FSCACHE */
 
 #endif /* _CIFS_FSCACHE_H */
index 449b6cf09b09dbc15e90f311e09bc011a0157b44..867b7cdc794a221a6eb21257d20bdc3f9e516248 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;
@@ -120,6 +120,33 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
        cifs_i->invalid_mapping = true;
 }
 
+/*
+ * copy nlink to the inode, unless it wasn't provided.  Provide
+ * sane values if we don't have an existing one and none was provided
+ */
+static void
+cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
+{
+       /*
+        * if we're in a situation where we can't trust what we
+        * got from the server (readdir, some non-unix cases)
+        * fake reasonable values
+        */
+       if (fattr->cf_flags & CIFS_FATTR_UNKNOWN_NLINK) {
+               /* only provide fake values on a new inode */
+               if (inode->i_state & I_NEW) {
+                       if (fattr->cf_cifsattrs & ATTR_DIRECTORY)
+                               set_nlink(inode, 2);
+                       else
+                               set_nlink(inode, 1);
+               }
+               return;
+       }
+
+       /* we trust the server, so update it */
+       set_nlink(inode, fattr->cf_nlink);
+}
+
 /* populate an inode with info from a cifs_fattr struct */
 void
 cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
@@ -134,7 +161,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
        inode->i_mtime = fattr->cf_mtime;
        inode->i_ctime = fattr->cf_ctime;
        inode->i_rdev = fattr->cf_rdev;
-       set_nlink(inode, fattr->cf_nlink);
+       cifs_nlink_fattr_to_inode(inode, fattr);
        inode->i_uid = fattr->cf_uid;
        inode->i_gid = fattr->cf_gid;
 
@@ -541,6 +568,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
        fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
        fattr->cf_createtime = le64_to_cpu(info->CreationTime);
 
+       fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
        if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
                fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
                fattr->cf_dtype = DT_DIR;
@@ -548,7 +576,12 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
                 * Server can return wrong NumberOfLinks value for directories
                 * when Unix extensions are disabled - fake it.
                 */
-               fattr->cf_nlink = 2;
+               if (!tcon->unix_ext)
+                       fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
+       } 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;
@@ -557,11 +590,15 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
                if (fattr->cf_cifsattrs & ATTR_READONLY)
                        fattr->cf_mode &= ~(S_IWUGO);
 
-               fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
-               if (fattr->cf_nlink < 1) {
-                       cifs_dbg(1, "replacing bogus file nlink value %u\n",
+               /*
+                * Don't accept zero nlink from non-unix servers unless
+                * delete is pending.  Instead mark it as unknown.
+                */
+               if ((fattr->cf_nlink < 1) && !tcon->unix_ext &&
+                   !info->DeletePending) {
+                       cifs_dbg(1, "bogus file nlink value %u\n",
                                fattr->cf_nlink);
-                       fattr->cf_nlink = 1;
+                       fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
                }
        }
 
@@ -646,7 +683,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 +1694,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 +1837,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 +1889,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 af847e1cf1c1985f5ddadd07e10dbc0e38a162a2..651a5279607b968a255a528e5411e4f4b39ca438 100644 (file)
@@ -780,7 +780,9 @@ static const struct {
        ERRDOS, ERRnoaccess, 0xc0000290}, {
        ERRDOS, ERRbadfunc, 0xc000029c}, {
        ERRDOS, ERRsymlink, NT_STATUS_STOPPED_ON_SYMLINK}, {
-       ERRDOS, ERRinvlevel, 0x007c0001}, };
+       ERRDOS, ERRinvlevel, 0x007c0001}, {
+       0, 0, 0 }
+};
 
 /*****************************************************************************
  Print an error message from the status code
index 69d2c826a23badc552bb686b518beaea297b473c..53a75f3d0179231d395611f61f2897c9a52f33de 100644 (file)
@@ -172,11 +172,17 @@ 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;
        }
 
+       /* non-unix readdir doesn't provide nlink */
+       fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
+
        if (fattr->cf_cifsattrs & ATTR_READONLY)
                fattr->cf_mode &= ~S_IWUGO;
 
index 08dd37bb23aac8ea04fe979743f8c963990a80f7..e87387dbf39fa1d24b19f245e86da4c907b0fdaf 100644 (file)
 #include <linux/slab.h>
 #include "cifs_spnego.h"
 
-/*
- * Checks if this is the first smb session to be reconnected after
- * the socket has been reestablished (so we know whether to use vc 0).
- * Called while holding the cifs_tcp_ses_lock, so do not block
- */
-static bool is_first_ses_reconnect(struct cifs_ses *ses)
-{
-       struct list_head *tmp;
-       struct cifs_ses *tmp_ses;
-
-       list_for_each(tmp, &ses->server->smb_ses_list) {
-               tmp_ses = list_entry(tmp, struct cifs_ses,
-                                    smb_ses_list);
-               if (tmp_ses->need_reconnect == false)
-                       return false;
-       }
-       /* could not find a session that was already connected,
-          this must be the first one we are reconnecting */
-       return true;
-}
-
-/*
- *     vc number 0 is treated specially by some servers, and should be the
- *      first one we request.  After that we can use vcnumbers up to maxvcs,
- *     one for each smb session (some Windows versions set maxvcs incorrectly
- *     so maxvc=1 can be ignored).  If we have too many vcs, we can reuse
- *     any vc but zero (some servers reset the connection on vcnum zero)
- *
- */
-static __le16 get_next_vcnum(struct cifs_ses *ses)
-{
-       __u16 vcnum = 0;
-       struct list_head *tmp;
-       struct cifs_ses *tmp_ses;
-       __u16 max_vcs = ses->server->max_vcs;
-       __u16 i;
-       int free_vc_found = 0;
-
-       /* Quoting the MS-SMB specification: "Windows-based SMB servers set this
-       field to one but do not enforce this limit, which allows an SMB client
-       to establish more virtual circuits than allowed by this value ... but
-       other server implementations can enforce this limit." */
-       if (max_vcs < 2)
-               max_vcs = 0xFFFF;
-
-       spin_lock(&cifs_tcp_ses_lock);
-       if ((ses->need_reconnect) && is_first_ses_reconnect(ses))
-                       goto get_vc_num_exit;  /* vcnum will be zero */
-       for (i = ses->server->srv_count - 1; i < max_vcs; i++) {
-               if (i == 0) /* this is the only connection, use vc 0 */
-                       break;
-
-               free_vc_found = 1;
-
-               list_for_each(tmp, &ses->server->smb_ses_list) {
-                       tmp_ses = list_entry(tmp, struct cifs_ses,
-                                            smb_ses_list);
-                       if (tmp_ses->vcnum == i) {
-                               free_vc_found = 0;
-                               break; /* found duplicate, try next vcnum */
-                       }
-               }
-               if (free_vc_found)
-                       break; /* we found a vcnumber that will work - use it */
-       }
-
-       if (i == 0)
-               vcnum = 0; /* for most common case, ie if one smb session, use
-                             vc zero.  Also for case when no free vcnum, zero
-                             is safest to send (some clients only send zero) */
-       else if (free_vc_found == 0)
-               vcnum = 1;  /* we can not reuse vc=0 safely, since some servers
-                               reset all uids on that, but 1 is ok. */
-       else
-               vcnum = i;
-       ses->vcnum = vcnum;
-get_vc_num_exit:
-       spin_unlock(&cifs_tcp_ses_lock);
-
-       return cpu_to_le16(vcnum);
-}
-
 static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
 {
        __u32 capabilities = 0;
@@ -128,7 +46,7 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
                                        CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4,
                                        USHRT_MAX));
        pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
-       pSMB->req.VcNumber = get_next_vcnum(ses);
+       pSMB->req.VcNumber = __constant_cpu_to_le16(1);
 
        /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
 
@@ -226,7 +144,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 +164,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 +346,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 +385,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 +421,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 +437,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);
@@ -580,9 +500,9 @@ select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
                                return NTLMv2;
                        if (global_secflags & CIFSSEC_MAY_NTLM)
                                return NTLM;
-                       /* Fallthrough */
                default:
-                       return Unspecified;
+                       /* Fallthrough to attempt LANMAN authentication next */
+                       break;
                }
        case CIFS_NEGFLAVOR_LANMAN:
                switch (requested) {
@@ -629,7 +549,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 +561,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 +738,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 +929,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..edccb5252462b6b465d3d71cb7d3de20e8d2be9a 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;
 }
 
@@ -645,6 +687,10 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
        else
                return -EIO;
 
+       /* no need to send SMB logoff if uid already closed due to reconnect */
+       if (ses->need_reconnect)
+               goto smb2_session_already_dead;
+
        rc = small_smb2_init(SMB2_LOGOFF, NULL, (void **) &req);
        if (rc)
                return rc;
@@ -659,6 +705,8 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
         * No tcon so can't do
         * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
         */
+
+smb2_session_already_dead:
        return rc;
 }
 
@@ -813,39 +861,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 +909,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 +976,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 +984,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 +1056,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 +1070,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 +1090,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 +1109,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;
index d952ee48f4dcc629a5d1e91c3470cbd2bd6d1aec..a4b2391fe66e4e11cea93e7396b987c335d43823 100644 (file)
 #define FSCTL_QUERY_NETWORK_INTERFACE_INFO 0x001401FC /* BB add struct */
 #define FSCTL_SRV_READ_HASH          0x001441BB /* BB add struct */
 
+/* See FSCC 2.1.2.5 */
 #define IO_REPARSE_TAG_MOUNT_POINT   0xA0000003
 #define IO_REPARSE_TAG_HSM           0xC0000004
 #define IO_REPARSE_TAG_SIS           0x80000007
+#define IO_REPARSE_TAG_HSM2          0x80000006
+#define IO_REPARSE_TAG_DRIVER_EXTENDER 0x80000005
+/* Used by the DFS filter. See MS-DFSC */
+#define IO_REPARSE_TAG_DFS           0x8000000A
+/* Used by the DFS filter See MS-DFSC */
+#define IO_REPARSE_TAG_DFSR          0x80000012
+#define IO_REPARSE_TAG_FILTER_MANAGER 0x8000000B
+/* See section MS-FSCC 2.1.2.4 */
+#define IO_REPARSE_TAG_SYMLINK       0xA000000C
+#define IO_REPARSE_TAG_DEDUP         0x80000013
+#define IO_REPARSE_APPXSTREAM       0xC0000014
+/* NFS symlinks, Win 8/SMB3 and later */
+#define IO_REPARSE_TAG_NFS           0x80000014
 
 /* fsctl flags */
 /* If Flags is set to this value, the request is an FSCTL not ioctl request */
index 6fdcb1b4a106747779ae77ed365116256e79edec..800b938e4061768f5f55ee414b45afa56e6d6aa2 100644 (file)
@@ -410,8 +410,13 @@ static int
 wait_for_free_request(struct TCP_Server_Info *server, const int timeout,
                      const int optype)
 {
-       return wait_for_free_credits(server, timeout,
-                               server->ops->get_credits_field(server, optype));
+       int *val;
+
+       val = server->ops->get_credits_field(server, optype);
+       /* Since an echo is already inflight, no need to wait to send another */
+       if (*val <= 0 && optype == CIFS_ECHO_OP)
+               return -EAGAIN;
+       return wait_for_free_credits(server, timeout, val);
 }
 
 static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
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 5aa53bc056bada2af9c3c6040498abcb9a3a3856..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;
        }
@@ -1031,34 +1212,55 @@ static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq
        return new;
 }
 
+/**
+ * enum d_walk_ret - action to talke during tree walk
+ * @D_WALK_CONTINUE:   contrinue walk
+ * @D_WALK_QUIT:       quit walk
+ * @D_WALK_NORETRY:    quit when retry is needed
+ * @D_WALK_SKIP:       skip this dentry and its children
+ */
+enum d_walk_ret {
+       D_WALK_CONTINUE,
+       D_WALK_QUIT,
+       D_WALK_NORETRY,
+       D_WALK_SKIP,
+};
 
-/*
- * Search for at least 1 mount point in the dentry's subdirs.
- * We descend to the next level whenever the d_subdirs
- * list is non-empty and continue searching.
- */
 /**
- * have_submounts - check for mounts over a dentry
- * @parent: dentry to check.
+ * d_walk - walk the dentry tree
+ * @parent:    start of walk
+ * @data:      data passed to @enter() and @finish()
+ * @enter:     callback when first entering the dentry
+ * @finish:    callback when successfully finished the walk
  *
- * Return true if the parent or its subdirectories contain
- * a mount point
+ * The @enter() and @finish() callbacks are called with d_lock held.
  */
-int have_submounts(struct dentry *parent)
+static void d_walk(struct dentry *parent, void *data,
+                  enum d_walk_ret (*enter)(void *, struct dentry *),
+                  void (*finish)(void *))
 {
        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;
-
-       if (d_mountpoint(parent))
-               goto positive;
        spin_lock(&this_parent->d_lock);
+
+       ret = enter(data, this_parent);
+       switch (ret) {
+       case D_WALK_CONTINUE:
+               break;
+       case D_WALK_QUIT:
+       case D_WALK_SKIP:
+               goto out_unlock;
+       case D_WALK_NORETRY:
+               retry = false;
+               break;
+       }
 repeat:
        next = this_parent->d_subdirs.next;
 resume:
@@ -1068,12 +1270,22 @@ resume:
                next = tmp->next;
 
                spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-               /* Have we found a mount point ? */
-               if (d_mountpoint(dentry)) {
+
+               ret = enter(data, dentry);
+               switch (ret) {
+               case D_WALK_CONTINUE:
+                       break;
+               case D_WALK_QUIT:
                        spin_unlock(&dentry->d_lock);
-                       spin_unlock(&this_parent->d_lock);
-                       goto positive;
+                       goto out_unlock;
+               case D_WALK_NORETRY:
+                       retry = false;
+                       break;
+               case D_WALK_SKIP:
+                       spin_unlock(&dentry->d_lock);
+                       continue;
                }
+
                if (!list_empty(&dentry->d_subdirs)) {
                        spin_unlock(&this_parent->d_lock);
                        spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_);
@@ -1088,34 +1300,98 @@ 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;
        }
-       spin_unlock(&this_parent->d_lock);
-       if (!locked && read_seqretry(&rename_lock, seq))
-               goto rename_retry;
-       if (locked)
-               write_sequnlock(&rename_lock);
-       return 0; /* No mount points found in tree */
-positive:
-       if (!locked && read_seqretry(&rename_lock, seq))
+       if (need_seqretry(&rename_lock, seq)) {
+               spin_unlock(&this_parent->d_lock);
                goto rename_retry;
-       if (locked)
-               write_sequnlock(&rename_lock);
-       return 1;
+       }
+       if (finish)
+               finish(data);
+
+out_unlock:
+       spin_unlock(&this_parent->d_lock);
+       done_seqretry(&rename_lock, seq);
+       return;
 
 rename_retry:
-       if (locked)
-               goto again;
-       locked = 1;
-       write_seqlock(&rename_lock);
+       if (!retry)
+               return;
+       seq = 1;
        goto again;
 }
+
+/*
+ * Search for at least 1 mount point in the dentry's subdirs.
+ * We descend to the next level whenever the d_subdirs
+ * list is non-empty and continue searching.
+ */
+
+/**
+ * have_submounts - check for mounts over a dentry
+ * @parent: dentry to check.
+ *
+ * Return true if the parent or its subdirectories contain
+ * a mount point
+ */
+
+static enum d_walk_ret check_mount(void *data, struct dentry *dentry)
+{
+       int *ret = data;
+       if (d_mountpoint(dentry)) {
+               *ret = 1;
+               return D_WALK_QUIT;
+       }
+       return D_WALK_CONTINUE;
+}
+
+int have_submounts(struct dentry *parent)
+{
+       int ret = 0;
+
+       d_walk(parent, &ret, check_mount, NULL);
+
+       return ret;
+}
 EXPORT_SYMBOL(have_submounts);
 
+/*
+ * Called by mount code to set a mountpoint and check if the mountpoint is
+ * reachable (e.g. NFS can unhash a directory dentry and then the complete
+ * subtree can become unreachable).
+ *
+ * Only one of check_submounts_and_drop() and d_set_mounted() must succeed.  For
+ * this reason take rename_lock and d_lock on dentry and ancestors.
+ */
+int d_set_mounted(struct dentry *dentry)
+{
+       struct dentry *p;
+       int ret = -ENOENT;
+       write_seqlock(&rename_lock);
+       for (p = dentry->d_parent; !IS_ROOT(p); p = p->d_parent) {
+               /* Need exclusion wrt. check_submounts_and_drop() */
+               spin_lock(&p->d_lock);
+               if (unlikely(d_unhashed(p))) {
+                       spin_unlock(&p->d_lock);
+                       goto out;
+               }
+               spin_unlock(&p->d_lock);
+       }
+       spin_lock(&dentry->d_lock);
+       if (!d_unlinked(dentry)) {
+               dentry->d_flags |= DCACHE_MOUNTED;
+               ret = 0;
+       }
+       spin_unlock(&dentry->d_lock);
+out:
+       write_sequnlock(&rename_lock);
+       return ret;
+}
+
 /*
  * Search the dentry child list of the specified parent,
  * and move any unused dentries to the end of the unused
@@ -1130,93 +1406,51 @@ EXPORT_SYMBOL(have_submounts);
  * drop the lock and return early due to latency
  * constraints.
  */
-static int select_parent(struct dentry *parent, struct list_head *dispose)
-{
-       struct dentry *this_parent;
-       struct list_head *next;
-       unsigned seq;
-       int found = 0;
-       int locked = 0;
 
-       seq = read_seqbegin(&rename_lock);
-again:
-       this_parent = parent;
-       spin_lock(&this_parent->d_lock);
-repeat:
-       next = this_parent->d_subdirs.next;
-resume:
-       while (next != &this_parent->d_subdirs) {
-               struct list_head *tmp = next;
-               struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
-               next = tmp->next;
+struct select_data {
+       struct dentry *start;
+       struct list_head dispose;
+       int found;
+};
 
-               spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+static enum d_walk_ret select_collect(void *_data, struct dentry *dentry)
+{
+       struct select_data *data = _data;
+       enum d_walk_ret ret = D_WALK_CONTINUE;
 
-               /*
-                * move only zero ref count dentries to the dispose list.
-                *
-                * Those which are presently on the shrink list, being processed
-                * by shrink_dentry_list(), shouldn't be moved.  Otherwise the
-                * loop in shrink_dcache_parent() might not make any progress
-                * and loop forever.
-                */
-               if (dentry->d_lockref.count) {
-                       dentry_lru_del(dentry);
-               } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
-                       dentry_lru_move_list(dentry, dispose);
-                       dentry->d_flags |= DCACHE_SHRINK_LIST;
-                       found++;
-               }
-               /*
-                * We can return to the caller if we have found some (this
-                * ensures forward progress). We'll be coming back to find
-                * the rest.
-                */
-               if (found && need_resched()) {
-                       spin_unlock(&dentry->d_lock);
-                       goto out;
-               }
+       if (data->start == dentry)
+               goto out;
 
+       /*
+        * move only zero ref count dentries to the dispose list.
+        *
+        * Those which are presently on the shrink list, being processed
+        * by shrink_dentry_list(), shouldn't be moved.  Otherwise the
+        * loop in shrink_dcache_parent() might not make any progress
+        * and loop forever.
+        */
+       if (dentry->d_lockref.count) {
+               dentry_lru_del(dentry);
+       } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
                /*
-                * Descend a level if the d_subdirs list is non-empty.
+                * We can't use d_lru_shrink_move() because we
+                * need to get the global LRU lock and do the
+                * LRU accounting.
                 */
-               if (!list_empty(&dentry->d_subdirs)) {
-                       spin_unlock(&this_parent->d_lock);
-                       spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_);
-                       this_parent = dentry;
-                       spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_);
-                       goto repeat;
-               }
-
-               spin_unlock(&dentry->d_lock);
+               d_lru_del(dentry);
+               d_shrink_add(dentry, &data->dispose);
+               data->found++;
+               ret = D_WALK_NORETRY;
        }
        /*
-        * All done at this level ... ascend and resume the search.
+        * We can return to the caller if we have found some (this
+        * ensures forward progress). We'll be coming back to find
+        * the rest.
         */
-       if (this_parent != parent) {
-               struct dentry *child = this_parent;
-               this_parent = try_to_ascend(this_parent, locked, seq);
-               if (!this_parent)
-                       goto rename_retry;
-               next = child->d_u.d_child.next;
-               goto resume;
-       }
+       if (data->found && need_resched())
+               ret = D_WALK_QUIT;
 out:
-       spin_unlock(&this_parent->d_lock);
-       if (!locked && read_seqretry(&rename_lock, seq))
-               goto rename_retry;
-       if (locked)
-               write_sequnlock(&rename_lock);
-       return found;
-
-rename_retry:
-       if (found)
-               return found;
-       if (locked)
-               goto again;
-       locked = 1;
-       write_seqlock(&rename_lock);
-       goto again;
+       return ret;
 }
 
 /**
@@ -1225,18 +1459,90 @@ rename_retry:
  *
  * Prune the dcache to remove unused children of the parent dentry.
  */
-void shrink_dcache_parent(struct dentry * parent)
+void shrink_dcache_parent(struct dentry *parent)
 {
-       LIST_HEAD(dispose);
-       int found;
+       for (;;) {
+               struct select_data data;
 
-       while ((found = select_parent(parent, &dispose)) != 0) {
-               shrink_dentry_list(&dispose);
+               INIT_LIST_HEAD(&data.dispose);
+               data.start = parent;
+               data.found = 0;
+
+               d_walk(parent, &data, select_collect, NULL);
+               if (!data.found)
+                       break;
+
+               shrink_dentry_list(&data.dispose);
                cond_resched();
        }
 }
 EXPORT_SYMBOL(shrink_dcache_parent);
 
+static enum d_walk_ret check_and_collect(void *_data, struct dentry *dentry)
+{
+       struct select_data *data = _data;
+
+       if (d_mountpoint(dentry)) {
+               data->found = -EBUSY;
+               return D_WALK_QUIT;
+       }
+
+       return select_collect(_data, dentry);
+}
+
+static void check_and_drop(void *_data)
+{
+       struct select_data *data = _data;
+
+       if (d_mountpoint(data->start))
+               data->found = -EBUSY;
+       if (!data->found)
+               __d_drop(data->start);
+}
+
+/**
+ * check_submounts_and_drop - prune dcache, check for submounts and drop
+ *
+ * All done as a single atomic operation relative to has_unlinked_ancestor().
+ * Returns 0 if successfully unhashed @parent.  If there were submounts then
+ * return -EBUSY.
+ *
+ * @dentry: dentry to prune and drop
+ */
+int check_submounts_and_drop(struct dentry *dentry)
+{
+       int ret = 0;
+
+       /* Negative dentries can be dropped without further checks */
+       if (!dentry->d_inode) {
+               d_drop(dentry);
+               goto out;
+       }
+
+       for (;;) {
+               struct select_data data;
+
+               INIT_LIST_HEAD(&data.dispose);
+               data.start = dentry;
+               data.found = 0;
+
+               d_walk(dentry, &data, check_and_collect, check_and_drop);
+               ret = data.found;
+
+               if (!list_empty(&data.dispose))
+                       shrink_dentry_list(&data.dispose);
+
+               if (ret <= 0)
+                       break;
+
+               cond_resched();
+       }
+
+out:
+       return ret;
+}
+EXPORT_SYMBOL(check_submounts_and_drop);
+
 /**
  * __d_alloc   -       allocate a dcache entry
  * @sb: filesystem it will belong to
@@ -2519,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;
 }
 
 /**
@@ -2531,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,
@@ -2540,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;
 }
 
@@ -2616,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)
@@ -2637,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)
@@ -2671,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
@@ -2703,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);
@@ -2742,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;
 }
 
 /*
@@ -2753,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);
@@ -2784,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);
 
@@ -2799,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)
@@ -2807,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;
@@ -2815,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
@@ -2837,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;
@@ -2868,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;
 }
 
@@ -2928,68 +3304,24 @@ int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
        return result;
 }
 
-void d_genocide(struct dentry *root)
+static enum d_walk_ret d_genocide_kill(void *data, struct dentry *dentry)
 {
-       struct dentry *this_parent;
-       struct list_head *next;
-       unsigned seq;
-       int locked = 0;
+       struct dentry *root = data;
+       if (dentry != root) {
+               if (d_unhashed(dentry) || !dentry->d_inode)
+                       return D_WALK_SKIP;
 
-       seq = read_seqbegin(&rename_lock);
-again:
-       this_parent = root;
-       spin_lock(&this_parent->d_lock);
-repeat:
-       next = this_parent->d_subdirs.next;
-resume:
-       while (next != &this_parent->d_subdirs) {
-               struct list_head *tmp = next;
-               struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
-               next = tmp->next;
-
-               spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-               if (d_unhashed(dentry) || !dentry->d_inode) {
-                       spin_unlock(&dentry->d_lock);
-                       continue;
-               }
-               if (!list_empty(&dentry->d_subdirs)) {
-                       spin_unlock(&this_parent->d_lock);
-                       spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_);
-                       this_parent = dentry;
-                       spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_);
-                       goto repeat;
-               }
                if (!(dentry->d_flags & DCACHE_GENOCIDE)) {
                        dentry->d_flags |= DCACHE_GENOCIDE;
                        dentry->d_lockref.count--;
                }
-               spin_unlock(&dentry->d_lock);
-       }
-       if (this_parent != root) {
-               struct dentry *child = this_parent;
-               if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
-                       this_parent->d_flags |= DCACHE_GENOCIDE;
-                       this_parent->d_lockref.count--;
-               }
-               this_parent = try_to_ascend(this_parent, locked, seq);
-               if (!this_parent)
-                       goto rename_retry;
-               next = child->d_u.d_child.next;
-               goto resume;
        }
-       spin_unlock(&this_parent->d_lock);
-       if (!locked && read_seqretry(&rename_lock, seq))
-               goto rename_retry;
-       if (locked)
-               write_sequnlock(&rename_lock);
-       return;
+       return D_WALK_CONTINUE;
+}
 
-rename_retry:
-       if (locked)
-               goto again;
-       locked = 1;
-       write_seqlock(&rename_lock);
-       goto again;
+void d_genocide(struct dentry *parent)
+{
+       d_walk(parent, parent, d_genocide_kill, NULL);
 }
 
 void d_tmpfile(struct dentry *dentry, struct inode *inode)
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 1194b1f0f8396c934ab6a382deadab6c0a6c4c2f..f8cde46de9cd77c3047182e94164bdfdac4a317d 100644 (file)
@@ -1783,7 +1783,7 @@ retry:
                d_tmpfile(dentry, inode);
                err = ext3_orphan_add(handle, inode);
                if (err)
-                       goto err_drop_inode;
+                       goto err_unlock_inode;
                mark_inode_dirty(inode);
                unlock_new_inode(inode);
        }
@@ -1791,10 +1791,9 @@ retry:
        if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
        return err;
-err_drop_inode:
+err_unlock_inode:
        ext3_journal_stop(handle);
        unlock_new_inode(inode);
-       iput(inode);
        return err;
 }
 
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..e274e9c1171f9095829aff07224dfff650a85ed2 100644 (file)
@@ -2563,7 +2563,7 @@ retry:
                        break;
        }
        blk_finish_plug(&plug);
-       if (!ret && !cycled) {
+       if (!ret && !cycled && wbc->nr_to_write > 0) {
                cycled = 1;
                mpd.last_page = writeback_index - 1;
                mpd.first_page = 0;
@@ -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 1bec5a5c1e45a29e9ead318987ec03d803104c5a..5a0408d7b1147094c3e82b6d11750b33396b7732 100644 (file)
@@ -2319,7 +2319,7 @@ retry:
                d_tmpfile(dentry, inode);
                err = ext4_orphan_add(handle, inode);
                if (err)
-                       goto err_drop_inode;
+                       goto err_unlock_inode;
                mark_inode_dirty(inode);
                unlock_new_inode(inode);
        }
@@ -2328,10 +2328,9 @@ retry:
        if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
        return err;
-err_drop_inode:
+err_unlock_inode:
        ext4_journal_stop(handle);
        unlock_new_inode(inode);
-       iput(inode);
        return err;
 }
 
index c081e34f717f6903492acd3c4bc92d26dc888e7e..03e9bebba1989ef20263fbd1656959b764927b03 100644 (file)
@@ -1350,6 +1350,8 @@ retry:
                                    s_min_extra_isize) {
                                        tried_min_extra_isize++;
                                        new_extra_isize = s_min_extra_isize;
+                                       kfree(is); is = NULL;
+                                       kfree(bs); bs = NULL;
                                        goto retry;
                                }
                                error = -1;
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 72a5d5b04494ded2468bc4a2f5f30e30c9ca12f7..b7989f2ab4c471f92238fa29d50e7b6d357d8c87 100644 (file)
@@ -182,10 +182,12 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
        struct inode *inode;
        struct dentry *parent;
        struct fuse_conn *fc;
+       struct fuse_inode *fi;
+       int ret;
 
        inode = ACCESS_ONCE(entry->d_inode);
        if (inode && is_bad_inode(inode))
-               return 0;
+               goto invalid;
        else if (fuse_dentry_time(entry) < get_jiffies_64()) {
                int err;
                struct fuse_entry_out outarg;
@@ -195,20 +197,23 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
 
                /* For negative dentries, always do a fresh lookup */
                if (!inode)
-                       return 0;
+                       goto invalid;
 
+               ret = -ECHILD;
                if (flags & LOOKUP_RCU)
-                       return -ECHILD;
+                       goto out;
 
                fc = get_fuse_conn(inode);
                req = fuse_get_req_nopages(fc);
+               ret = PTR_ERR(req);
                if (IS_ERR(req))
-                       return 0;
+                       goto out;
 
                forget = fuse_alloc_forget();
                if (!forget) {
                        fuse_put_request(fc, req);
-                       return 0;
+                       ret = -ENOMEM;
+                       goto out;
                }
 
                attr_version = fuse_get_attr_version(fc);
@@ -224,10 +229,10 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
                if (!err && !outarg.nodeid)
                        err = -ENOENT;
                if (!err) {
-                       struct fuse_inode *fi = get_fuse_inode(inode);
+                       fi = get_fuse_inode(inode);
                        if (outarg.nodeid != get_node_id(inode)) {
                                fuse_queue_forget(fc, forget, outarg.nodeid, 1);
-                               return 0;
+                               goto invalid;
                        }
                        spin_lock(&fc->lock);
                        fi->nlookup++;
@@ -235,21 +240,33 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
                }
                kfree(forget);
                if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
-                       return 0;
+                       goto invalid;
 
                fuse_change_attributes(inode, &outarg.attr,
                                       entry_attr_timeout(&outarg),
                                       attr_version);
                fuse_change_entry_timeout(entry, &outarg);
        } else if (inode) {
-               fc = get_fuse_conn(inode);
-               if (fc->readdirplus_auto) {
+               fi = get_fuse_inode(inode);
+               if (flags & LOOKUP_RCU) {
+                       if (test_bit(FUSE_I_INIT_RDPLUS, &fi->state))
+                               return -ECHILD;
+               } else if (test_and_clear_bit(FUSE_I_INIT_RDPLUS, &fi->state)) {
                        parent = dget_parent(entry);
                        fuse_advise_use_readdirplus(parent->d_inode);
                        dput(parent);
                }
        }
-       return 1;
+       ret = 1;
+out:
+       return ret;
+
+invalid:
+       ret = 0;
+
+       if (!(flags & LOOKUP_RCU) && check_submounts_and_drop(entry) != 0)
+               ret = 1;
+       goto out;
 }
 
 static int invalid_nodeid(u64 nodeid)
@@ -267,26 +284,6 @@ int fuse_valid_type(int m)
                S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
 }
 
-/*
- * Add a directory inode to a dentry, ensuring that no other dentry
- * refers to this inode.  Called with fc->inst_mutex.
- */
-static struct dentry *fuse_d_add_directory(struct dentry *entry,
-                                          struct inode *inode)
-{
-       struct dentry *alias = d_find_alias(inode);
-       if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
-               /* This tries to shrink the subtree below alias */
-               fuse_invalidate_entry(alias);
-               dput(alias);
-               if (!hlist_empty(&inode->i_dentry))
-                       return ERR_PTR(-EBUSY);
-       } else {
-               dput(alias);
-       }
-       return d_splice_alias(inode, entry);
-}
-
 int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
                     struct fuse_entry_out *outarg, struct inode **inode)
 {
@@ -345,6 +342,24 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
        return err;
 }
 
+static struct dentry *fuse_materialise_dentry(struct dentry *dentry,
+                                             struct inode *inode)
+{
+       struct dentry *newent;
+
+       if (inode && S_ISDIR(inode->i_mode)) {
+               struct fuse_conn *fc = get_fuse_conn(inode);
+
+               mutex_lock(&fc->inst_mutex);
+               newent = d_materialise_unique(dentry, inode);
+               mutex_unlock(&fc->inst_mutex);
+       } else {
+               newent = d_materialise_unique(dentry, inode);
+       }
+
+       return newent;
+}
+
 static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
                                  unsigned int flags)
 {
@@ -352,7 +367,6 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
        struct fuse_entry_out outarg;
        struct inode *inode;
        struct dentry *newent;
-       struct fuse_conn *fc = get_fuse_conn(dir);
        bool outarg_valid = true;
 
        err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
@@ -368,16 +382,10 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
        if (inode && get_node_id(inode) == FUSE_ROOT_ID)
                goto out_iput;
 
-       if (inode && S_ISDIR(inode->i_mode)) {
-               mutex_lock(&fc->inst_mutex);
-               newent = fuse_d_add_directory(entry, inode);
-               mutex_unlock(&fc->inst_mutex);
-               err = PTR_ERR(newent);
-               if (IS_ERR(newent))
-                       goto out_iput;
-       } else {
-               newent = d_splice_alias(inode, entry);
-       }
+       newent = fuse_materialise_dentry(entry, inode);
+       err = PTR_ERR(newent);
+       if (IS_ERR(newent))
+               goto out_err;
 
        entry = newent ? newent : entry;
        if (outarg_valid)
@@ -1060,6 +1068,8 @@ static int fuse_access(struct inode *inode, int mask)
        struct fuse_access_in inarg;
        int err;
 
+       BUG_ON(mask & MAY_NOT_BLOCK);
+
        if (fc->no_access)
                return 0;
 
@@ -1147,9 +1157,6 @@ static int fuse_permission(struct inode *inode, int mask)
                   noticed immediately, only after the attribute
                   timeout has expired */
        } else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
-               if (mask & MAY_NOT_BLOCK)
-                       return -ECHILD;
-
                err = fuse_access(inode, mask);
        } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
                if (!(inode->i_mode & S_IXUGO)) {
@@ -1174,6 +1181,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))
@@ -1275,18 +1284,10 @@ static int fuse_direntplus_link(struct file *file,
        if (!inode)
                goto out;
 
-       if (S_ISDIR(inode->i_mode)) {
-               mutex_lock(&fc->inst_mutex);
-               alias = fuse_d_add_directory(dentry, inode);
-               mutex_unlock(&fc->inst_mutex);
-               err = PTR_ERR(alias);
-               if (IS_ERR(alias)) {
-                       iput(inode);
-                       goto out;
-               }
-       } else {
-               alias = d_splice_alias(inode, dentry);
-       }
+       alias = fuse_materialise_dentry(dentry, inode);
+       err = PTR_ERR(alias);
+       if (IS_ERR(alias))
+               goto out;
 
        if (alias) {
                dput(dentry);
@@ -1294,6 +1295,8 @@ static int fuse_direntplus_link(struct file *file,
        }
 
 found:
+       if (fc->readdirplus_auto)
+               set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state);
        fuse_change_entry_timeout(dentry, o);
 
        err = 0;
@@ -1320,6 +1323,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
@@ -1590,6 +1595,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;
@@ -1617,8 +1623,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));
@@ -1676,16 +1684,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;
 }
 
@@ -1749,6 +1759,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;
 }
 
@@ -1878,6 +1890,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..4598345ab87d683dba75022a4a07981dbfb458ed 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:
@@ -2460,6 +2467,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
 {
        struct fuse_file *ff = file->private_data;
        struct inode *inode = file->f_inode;
+       struct fuse_inode *fi = get_fuse_inode(inode);
        struct fuse_conn *fc = ff->fc;
        struct fuse_req *req;
        struct fuse_fallocate_in inarg = {
@@ -2477,10 +2485,20 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
 
        if (lock_inode) {
                mutex_lock(&inode->i_mutex);
-               if (mode & FALLOC_FL_PUNCH_HOLE)
-                       fuse_set_nowrite(inode);
+               if (mode & FALLOC_FL_PUNCH_HOLE) {
+                       loff_t endbyte = offset + length - 1;
+                       err = filemap_write_and_wait_range(inode->i_mapping,
+                                                          offset, endbyte);
+                       if (err)
+                               goto out;
+
+                       fuse_sync_writes(inode);
+               }
        }
 
+       if (!(mode & FALLOC_FL_KEEP_SIZE))
+               set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
+
        req = fuse_get_req_nopages(fc);
        if (IS_ERR(req)) {
                err = PTR_ERR(req);
@@ -2513,11 +2531,11 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
        fuse_invalidate_attr(inode);
 
 out:
-       if (lock_inode) {
-               if (mode & FALLOC_FL_PUNCH_HOLE)
-                       fuse_release_nowrite(inode);
+       if (!(mode & FALLOC_FL_KEEP_SIZE))
+               clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
+
+       if (lock_inode)
                mutex_unlock(&inode->i_mutex);
-       }
 
        return err;
 }
index fde7249a3a9608c8c6e49be4316a1d155b7cdfba..5b9e6f3b6aef4fc55aaaaaa94666dd532c4fbffc 100644 (file)
@@ -115,6 +115,10 @@ struct fuse_inode {
 enum {
        /** Advise readdirplus  */
        FUSE_I_ADVISE_RDPLUS,
+       /** Initialized with readdirplus */
+       FUSE_I_INIT_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 f2448ab2aac54d99306140a192afa1c1d9e3dc46..d3a5d4e29ba5f37b10f4f0fd0043c7e9847b9923 100644 (file)
@@ -93,12 +93,9 @@ invalid_gunlock:
        if (!had_lock)
                gfs2_glock_dq_uninit(&d_gh);
 invalid:
-       if (inode && S_ISDIR(inode->i_mode)) {
-               if (have_submounts(dentry))
-                       goto valid;
-               shrink_dcache_parent(dentry);
-       }
-       d_drop(dentry);
+       if (check_submounts_and_drop(dentry) != 0)
+               goto valid;
+
        dput(parent);
        return 0;
 
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 7c5f01cf619d689d76ab51cc7cc221bead874cf4..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);
 
@@ -126,6 +131,9 @@ extern int invalidate_inodes(struct super_block *, bool);
  * dcache.c
  */
 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 ad8ea9bc2518e7fcf6fc3914d095eb6338a99693..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>
@@ -611,6 +611,7 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry)
 {
        struct list_head *chain = mountpoint_hashtable + hash(NULL, dentry);
        struct mountpoint *mp;
+       int ret;
 
        list_for_each_entry(mp, chain, m_hash) {
                if (mp->m_dentry == dentry) {
@@ -626,14 +627,12 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry)
        if (!mp)
                return ERR_PTR(-ENOMEM);
 
-       spin_lock(&dentry->d_lock);
-       if (d_unlinked(dentry)) {
-               spin_unlock(&dentry->d_lock);
+       ret = d_set_mounted(dentry);
+       if (ret) {
                kfree(mp);
-               return ERR_PTR(-ENOENT);
+               return ERR_PTR(ret);
        }
-       dentry->d_flags |= DCACHE_MOUNTED;
-       spin_unlock(&dentry->d_lock);
+
        mp->m_dentry = dentry;
        mp->m_count = 1;
        list_add(&mp->m_hash, chain);
@@ -831,6 +830,10 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
        if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY))
                mnt->mnt.mnt_flags |= MNT_LOCK_READONLY;
 
+       /* Don't allow unprivileged users to reveal what is under a mount */
+       if ((flag & CL_UNPRIVILEGED) && list_empty(&old->mnt_expire))
+               mnt->mnt.mnt_flags |= MNT_LOCKED;
+
        atomic_inc(&sb->s_active);
        mnt->mnt.mnt_sb = sb;
        mnt->mnt.mnt_root = dget(root);
@@ -1318,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);
@@ -1327,6 +1330,8 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
                goto dput_and_out;
        if (!check_mnt(mnt))
                goto dput_and_out;
+       if (mnt->mnt.mnt_flags & MNT_LOCKED)
+               goto dput_and_out;
 
        retval = do_umount(mnt, flags);
 dput_and_out:
@@ -1349,14 +1354,11 @@ SYSCALL_DEFINE1(oldumount, char __user *, name)
 
 #endif
 
-static bool mnt_ns_loop(struct path *path)
+static bool is_mnt_ns_file(struct dentry *dentry)
 {
-       /* Could bind mounting the mount namespace inode cause a
-        * mount namespace loop?
-        */
-       struct inode *inode = path->dentry->d_inode;
+       /* Is this a proxy for a mount namespace? */
+       struct inode *inode = dentry->d_inode;
        struct proc_ns *ei;
-       struct mnt_namespace *mnt_ns;
 
        if (!proc_ns_inode(inode))
                return false;
@@ -1365,7 +1367,19 @@ static bool mnt_ns_loop(struct path *path)
        if (ei->ns_ops != &mntns_operations)
                return false;
 
-       mnt_ns = ei->ns;
+       return true;
+}
+
+static bool mnt_ns_loop(struct dentry *dentry)
+{
+       /* Could bind mounting the mount namespace inode cause a
+        * mount namespace loop?
+        */
+       struct mnt_namespace *mnt_ns;
+       if (!is_mnt_ns_file(dentry))
+               return false;
+
+       mnt_ns = get_proc_ns(dentry->d_inode)->ns;
        return current->nsproxy->mnt_ns->seq >= mnt_ns->seq;
 }
 
@@ -1374,13 +1388,17 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
 {
        struct mount *res, *p, *q, *r, *parent;
 
-       if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt))
+       if (!(flag & CL_COPY_UNBINDABLE) && IS_MNT_UNBINDABLE(mnt))
+               return ERR_PTR(-EINVAL);
+
+       if (!(flag & CL_COPY_MNT_NS_FILE) && is_mnt_ns_file(dentry))
                return ERR_PTR(-EINVAL);
 
        res = q = clone_mnt(mnt, dentry, flag);
        if (IS_ERR(q))
                return q;
 
+       q->mnt.mnt_flags &= ~MNT_LOCKED;
        q->mnt_mountpoint = mnt->mnt_mountpoint;
 
        p = mnt;
@@ -1390,7 +1408,13 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
                        continue;
 
                for (s = r; s; s = next_mnt(s, r)) {
-                       if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(s)) {
+                       if (!(flag & CL_COPY_UNBINDABLE) &&
+                           IS_MNT_UNBINDABLE(s)) {
+                               s = skip_mnt_tree(s);
+                               continue;
+                       }
+                       if (!(flag & CL_COPY_MNT_NS_FILE) &&
+                           is_mnt_ns_file(s->mnt.mnt_root)) {
                                s = skip_mnt_tree(s);
                                continue;
                        }
@@ -1696,6 +1720,19 @@ static int do_change_type(struct path *path, int flag)
        return err;
 }
 
+static bool has_locked_children(struct mount *mnt, struct dentry *dentry)
+{
+       struct mount *child;
+       list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
+               if (!is_subdir(child->mnt_mountpoint, dentry))
+                       continue;
+
+               if (child->mnt.mnt_flags & MNT_LOCKED)
+                       return true;
+       }
+       return false;
+}
+
 /*
  * do loopback mount.
  */
@@ -1713,7 +1750,7 @@ static int do_loopback(struct path *path, const char *old_name,
                return err;
 
        err = -EINVAL;
-       if (mnt_ns_loop(&old_path))
+       if (mnt_ns_loop(old_path.dentry))
                goto out; 
 
        mp = lock_mount(path);
@@ -1731,8 +1768,11 @@ static int do_loopback(struct path *path, const char *old_name,
        if (!check_mnt(parent) || !check_mnt(old))
                goto out2;
 
+       if (!recurse && has_locked_children(old, old_path.dentry))
+               goto out2;
+
        if (recurse)
-               mnt = copy_tree(old, old_path.dentry, 0);
+               mnt = copy_tree(old, old_path.dentry, CL_COPY_MNT_NS_FILE);
        else
                mnt = clone_mnt(old, old_path.dentry, 0);
 
@@ -1741,6 +1781,8 @@ static int do_loopback(struct path *path, const char *old_name,
                goto out2;
        }
 
+       mnt->mnt.mnt_flags &= ~MNT_LOCKED;
+
        err = graft_tree(mnt, parent, mp);
        if (err) {
                br_write_lock(&vfsmount_lock);
@@ -1853,6 +1895,9 @@ static int do_move_mount(struct path *path, const char *old_name)
        if (!check_mnt(p) || !check_mnt(old))
                goto out1;
 
+       if (old->mnt.mnt_flags & MNT_LOCKED)
+               goto out1;
+
        err = -EINVAL;
        if (old_path.dentry != old_path.mnt->mnt_root)
                goto out1;
@@ -2389,7 +2434,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
 
        namespace_lock();
        /* First pass: copy the tree topology */
-       copy_flags = CL_COPY_ALL | CL_EXPIRE;
+       copy_flags = CL_COPY_UNBINDABLE | CL_EXPIRE;
        if (user_ns != mnt_ns->user_ns)
                copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED;
        new = copy_tree(old, old->mnt.mnt_root, copy_flags);
@@ -2424,6 +2469,10 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
                }
                p = next_mnt(p, old);
                q = next_mnt(q, new);
+               if (!q)
+                       break;
+               while (p->mnt.mnt_root != q->mnt.mnt_root)
+                       p = next_mnt(p, old);
        }
        namespace_unlock();
 
@@ -2630,6 +2679,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
                goto out4;
        if (!check_mnt(root_mnt) || !check_mnt(new_mnt))
                goto out4;
+       if (new_mnt->mnt.mnt_flags & MNT_LOCKED)
+               goto out4;
        error = -ENOENT;
        if (d_unlinked(new.dentry))
                goto out4;
@@ -2653,6 +2704,10 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
        br_write_lock(&vfsmount_lock);
        detach_mnt(new_mnt, &parent_path);
        detach_mnt(root_mnt, &root_parent);
+       if (root_mnt->mnt.mnt_flags & MNT_LOCKED) {
+               new_mnt->mnt.mnt_flags |= MNT_LOCKED;
+               root_mnt->mnt.mnt_flags &= ~MNT_LOCKED;
+       }
        /* mount old root on put_old */
        attach_mnt(root_mnt, old_mnt, old_mp);
        /* mount new_root on / */
@@ -2811,25 +2866,38 @@ bool current_chrooted(void)
        return chrooted;
 }
 
-void update_mnt_policy(struct user_namespace *userns)
+bool fs_fully_visible(struct file_system_type *type)
 {
        struct mnt_namespace *ns = current->nsproxy->mnt_ns;
        struct mount *mnt;
+       bool visible = false;
 
-       down_read(&namespace_sem);
+       if (unlikely(!ns))
+               return false;
+
+       namespace_lock();
        list_for_each_entry(mnt, &ns->list, mnt_list) {
-               switch (mnt->mnt.mnt_sb->s_magic) {
-               case SYSFS_MAGIC:
-                       userns->may_mount_sysfs = true;
-                       break;
-               case PROC_SUPER_MAGIC:
-                       userns->may_mount_proc = true;
-                       break;
+               struct mount *child;
+               if (mnt->mnt.mnt_sb->s_type != type)
+                       continue;
+
+               /* This mount is not fully visible if there are any child mounts
+                * that cover anything except for empty directories.
+                */
+               list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
+                       struct inode *inode = child->mnt_mountpoint->d_inode;
+                       if (!S_ISDIR(inode->i_mode))
+                               goto next;
+                       if (inode->i_nlink != 2)
+                               goto next;
                }
-               if (userns->may_mount_sysfs && userns->may_mount_proc)
-                       break;
+               visible = true;
+               goto found;
+       next:   ;
        }
-       up_read(&namespace_sem);
+found:
+       namespace_unlock();
+       return visible;
 }
 
 static void *mntns_get(struct task_struct *task)
@@ -2860,8 +2928,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns)
        struct path root;
 
        if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) ||
-           !nsown_capable(CAP_SYS_CHROOT) ||
-           !nsown_capable(CAP_SYS_ADMIN))
+           !ns_capable(current_user_ns(), CAP_SYS_CHROOT) ||
+           !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
                return -EPERM;
 
        if (fs->users != 1)
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 e474ca2b2bfea832d488536a807ae140073dd591..02b0df769e2db23d18d7787e27066ebaa684bbd0 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))
@@ -1135,14 +1139,13 @@ out_zap_parent:
        if (inode && S_ISDIR(inode->i_mode)) {
                /* Purge readdir caches. */
                nfs_zap_caches(inode);
-               /* If we have submounts, don't unhash ! */
-               if (have_submounts(dentry))
-                       goto out_valid;
                if (dentry->d_flags & DCACHE_DISCONNECTED)
                        goto out_valid;
-               shrink_dcache_parent(dentry);
        }
-       d_drop(dentry);
+       /* If we have submounts, don't unhash ! */
+       if (check_submounts_and_drop(dentry) != 0)
+               goto out_valid;
+
        dput(parent);
        dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n",
                        __func__, dentry->d_parent->d_name.name,
@@ -1313,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)
@@ -1339,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);
@@ -1387,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;
 }
 
@@ -1405,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 */
@@ -1413,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)) {
@@ -1423,6 +1435,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
                         */
                        return -ENOENT;
                }
+               lookup_flags = LOOKUP_OPEN|LOOKUP_DIRECTORY;
                goto no_open;
        }
 
@@ -1443,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);
+       inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr, opened);
        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);
@@ -1469,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;
@@ -1597,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;
@@ -1625,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;
@@ -1649,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;
@@ -1672,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;
 }
@@ -1705,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);
@@ -1714,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;
 }
@@ -1731,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);
@@ -1749,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);
@@ -1795,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,
@@ -1830,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);
@@ -1838,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);
@@ -1879,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
@@ -1925,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);
@@ -1965,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) {
@@ -1991,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);
@@ -2005,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)
@@ -2174,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;
@@ -2189,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)
@@ -2241,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 e5b804dd944c16a8adf4de17ee6588562cec55e8..77efaf15ec9019a2a6ed4527b214a166796497c4 100644 (file)
@@ -19,6 +19,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
        struct inode *dir;
        unsigned openflags = filp->f_flags;
        struct iattr attr;
+       int opened = 0;
        int err;
 
        /*
@@ -55,7 +56,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
                nfs_wb_all(inode);
        }
 
-       inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
+       inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, &opened);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                switch (err) {
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 95604f64cab86632d7a166ce588ea9ffd5d87e95..c7c295e556ed87501c069053d0c133e44dcadc97 100644 (file)
@@ -185,6 +185,7 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
        if (status)
                goto out_put;
 
+       smp_wmb();
        ds->ds_clp = clp;
        dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
 out:
@@ -801,34 +802,35 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
        struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr;
        struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
        struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
-
-       if (filelayout_test_devid_unavailable(devid))
-               return NULL;
+       struct nfs4_pnfs_ds *ret = ds;
 
        if (ds == NULL) {
                printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
                        __func__, ds_idx);
                filelayout_mark_devid_invalid(devid);
-               return NULL;
+               goto out;
        }
+       smp_rmb();
        if (ds->ds_clp)
-               return ds;
+               goto out_test_devid;
 
        if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) {
                struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
                int err;
 
                err = nfs4_ds_connect(s, ds);
-               if (err) {
+               if (err)
                        nfs4_mark_deviceid_unavailable(devid);
-                       ds = NULL;
-               }
                nfs4_clear_ds_conn_bit(ds);
        } else {
                /* Either ds is connected, or ds is NULL */
                nfs4_wait_ds_connect(ds);
        }
-       return ds;
+out_test_devid:
+       if (filelayout_test_devid_unavailable(devid))
+               ret = NULL;
+out:
+       return ret;
 }
 
 module_param(dataserver_retrans, uint, 0644);
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..d53d6785cba27f5c6442831e51eded9d04b054f3 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)
@@ -826,6 +912,7 @@ struct nfs4_opendata {
        struct iattr attrs;
        unsigned long timestamp;
        unsigned int rpc_done : 1;
+       unsigned int file_created : 1;
        unsigned int is_recover : 1;
        int rpc_status;
        int cancelled;
@@ -933,7 +1020,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 +1190,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 +1527,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 +1612,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 +1654,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 +1682,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 +1842,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;
@@ -1847,8 +1947,13 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
 
        nfs_fattr_map_and_free_names(server, &data->f_attr);
 
-       if (o_arg->open_flags & O_CREAT)
+       if (o_arg->open_flags & O_CREAT) {
                update_changeattr(dir, &o_res->cinfo);
+               if (o_arg->open_flags & O_EXCL)
+                       data->file_created = 1;
+               else if (o_res->cinfo.before != o_res->cinfo.after)
+                       data->file_created = 1;
+       }
        if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
                server->caps &= ~NFS_CAP_POSIX_LOCK;
        if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
@@ -1895,6 +2000,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 +2050,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 +2093,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. */
@@ -2089,7 +2197,8 @@ static int _nfs4_do_open(struct inode *dir,
                        struct nfs_open_context *ctx,
                        int flags,
                        struct iattr *sattr,
-                       struct nfs4_label *label)
+                       struct nfs4_label *label,
+                       int *opened)
 {
        struct nfs4_state_owner  *sp;
        struct nfs4_state     *state = NULL;
@@ -2159,6 +2268,8 @@ static int _nfs4_do_open(struct inode *dir,
                        nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
                }
        }
+       if (opendata->file_created)
+               *opened |= FILE_CREATED;
 
        if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
                *ctx_th = opendata->f_attr.mdsthreshold;
@@ -2187,7 +2298,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
                                        struct nfs_open_context *ctx,
                                        int flags,
                                        struct iattr *sattr,
-                                       struct nfs4_label *label)
+                                       struct nfs4_label *label,
+                                       int *opened)
 {
        struct nfs_server *server = NFS_SERVER(dir);
        struct nfs4_exception exception = { };
@@ -2195,8 +2307,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
        int status;
 
        do {
-               status = _nfs4_do_open(dir, ctx, flags, sattr, label);
+               status = _nfs4_do_open(dir, ctx, flags, sattr, label, opened);
                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 +2423,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 +2501,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 +2626,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);
@@ -2551,7 +2669,8 @@ out:
 }
 
 static struct inode *
-nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
+nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx,
+               int open_flags, struct iattr *attr, int *opened)
 {
        struct nfs4_state *state;
        struct nfs4_label l = {0, 0, 0, NULL}, *label = NULL;
@@ -2559,7 +2678,7 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags
        label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);
 
        /* Protect against concurrent sillydeletes */
-       state = nfs4_do_open(dir, ctx, open_flags, attr, label);
+       state = nfs4_do_open(dir, ctx, open_flags, attr, label, opened);
 
        nfs4_label_release_security(label);
 
@@ -2690,6 +2809,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 +2825,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 +2895,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 +3031,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 +3073,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 +3153,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 +3165,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 +3270,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 +3325,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;
@@ -3205,6 +3343,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        struct nfs4_label l, *ilabel = NULL;
        struct nfs_open_context *ctx;
        struct nfs4_state *state;
+       int opened = 0;
        int status = 0;
 
        ctx = alloc_nfs_open_context(dentry, FMODE_READ);
@@ -3214,7 +3353,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
 
        sattr->ia_mode &= ~current_umask();
-       state = nfs4_do_open(dir, ctx, flags, sattr, ilabel);
+       state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, &opened);
        if (IS_ERR(state)) {
                status = PTR_ERR(state);
                goto out;
@@ -3253,8 +3392,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 +3408,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 +3423,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 +3442,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 +3456,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 +3503,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 +3668,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 +3707,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 +3762,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 +3817,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 +3887,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 +4006,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 +4050,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 +4138,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 +4168,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 +4191,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 +4220,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 +4478,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 +4558,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 +4613,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 +4667,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 +4793,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 +4823,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 +4891,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 +4919,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 +4941,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 +4963,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 +4974,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 +5001,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 +5041,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 +5116,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 +5255,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 +5269,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 +5319,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 +5505,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 +5543,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 +5562,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 +5606,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 +5694,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 +5777,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 +5802,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 +5816,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 +5981,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 +6012,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 +6042,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 +6122,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 +6151,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 +6317,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 +6387,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 +6427,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 +6465,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 +6557,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 +6691,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 +6755,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 +6805,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 +6863,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 +6958,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 +7006,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 +7197,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 +7208,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 +7284,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 +7292,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 +7474,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 +7484,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 +7511,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 +7539,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:
@@ -7124,8 +7576,10 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
 {
        int err;
        struct page *page;
-       rpc_authflavor_t flavor;
+       rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
        struct nfs4_secinfo_flavors *flavors;
+       struct nfs4_secinfo4 *secinfo;
+       int i;
 
        page = alloc_page(GFP_KERNEL);
        if (!page) {
@@ -7147,9 +7601,31 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
        if (err)
                goto out_freepage;
 
-       flavor = nfs_find_best_sec(flavors);
-       if (err == 0)
-               err = nfs4_lookup_root_sec(server, fhandle, info, flavor);
+       for (i = 0; i < flavors->num_flavors; i++) {
+               secinfo = &flavors->flavors[i];
+
+               switch (secinfo->flavor) {
+               case RPC_AUTH_NULL:
+               case RPC_AUTH_UNIX:
+               case RPC_AUTH_GSS:
+                       flavor = rpcauth_get_pseudoflavor(secinfo->flavor,
+                                       &secinfo->flavor_info);
+                       break;
+               default:
+                       flavor = RPC_AUTH_MAXFLAVOR;
+                       break;
+               }
+
+               if (flavor != RPC_AUTH_MAXFLAVOR) {
+                       err = nfs4_lookup_root_sec(server, fhandle,
+                                                  info, flavor);
+                       if (!err)
+                               break;
+               }
+       }
+
+       if (flavor == RPC_AUTH_MAXFLAVOR)
+               err = -EPERM;
 
 out_freepage:
        put_page(page);
@@ -7174,11 +7650,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 +7727,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 +7750,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 +7764,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 +7840,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 +7850,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 +7861,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 +7870,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 +7893,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 +7913,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 +7934,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 +7956,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 0ba679866e504ec126720f3eb7b78e210703f538..da276640f7763d2463c0fa99cb832a86d243f10c 100644 (file)
@@ -94,6 +94,7 @@ void nilfs_forget_buffer(struct buffer_head *bh)
        clear_buffer_nilfs_volatile(bh);
        clear_buffer_nilfs_checked(bh);
        clear_buffer_nilfs_redirected(bh);
+       clear_buffer_async_write(bh);
        clear_buffer_dirty(bh);
        if (nilfs_page_buffers_clean(page))
                __nilfs_clear_page_dirty(page);
@@ -429,6 +430,7 @@ void nilfs_clear_dirty_page(struct page *page, bool silent)
                                        "discard block %llu, size %zu",
                                        (u64)bh->b_blocknr, bh->b_size);
                        }
+                       clear_buffer_async_write(bh);
                        clear_buffer_dirty(bh);
                        clear_buffer_nilfs_volatile(bh);
                        clear_buffer_nilfs_checked(bh);
index bd88a7461063bba02f31c6f873902c9c8e87e943..9f6b486b6c01a0e6711ca5930e78474d0739e35e 100644 (file)
@@ -665,7 +665,7 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode,
 
                bh = head = page_buffers(page);
                do {
-                       if (!buffer_dirty(bh))
+                       if (!buffer_dirty(bh) || buffer_async_write(bh))
                                continue;
                        get_bh(bh);
                        list_add_tail(&bh->b_assoc_buffers, listp);
@@ -699,7 +699,8 @@ static void nilfs_lookup_dirty_node_buffers(struct inode *inode,
                for (i = 0; i < pagevec_count(&pvec); i++) {
                        bh = head = page_buffers(pvec.pages[i]);
                        do {
-                               if (buffer_dirty(bh)) {
+                               if (buffer_dirty(bh) &&
+                                               !buffer_async_write(bh)) {
                                        get_bh(bh);
                                        list_add_tail(&bh->b_assoc_buffers,
                                                      listp);
@@ -1579,6 +1580,7 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci)
 
                list_for_each_entry(bh, &segbuf->sb_segsum_buffers,
                                    b_assoc_buffers) {
+                       set_buffer_async_write(bh);
                        if (bh->b_page != bd_page) {
                                if (bd_page) {
                                        lock_page(bd_page);
@@ -1592,6 +1594,7 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci)
 
                list_for_each_entry(bh, &segbuf->sb_payload_buffers,
                                    b_assoc_buffers) {
+                       set_buffer_async_write(bh);
                        if (bh == segbuf->sb_super_root) {
                                if (bh->b_page != bd_page) {
                                        lock_page(bd_page);
@@ -1677,6 +1680,7 @@ static void nilfs_abort_logs(struct list_head *logs, int err)
        list_for_each_entry(segbuf, logs, sb_list) {
                list_for_each_entry(bh, &segbuf->sb_segsum_buffers,
                                    b_assoc_buffers) {
+                       clear_buffer_async_write(bh);
                        if (bh->b_page != bd_page) {
                                if (bd_page)
                                        end_page_writeback(bd_page);
@@ -1686,6 +1690,7 @@ static void nilfs_abort_logs(struct list_head *logs, int err)
 
                list_for_each_entry(bh, &segbuf->sb_payload_buffers,
                                    b_assoc_buffers) {
+                       clear_buffer_async_write(bh);
                        if (bh == segbuf->sb_super_root) {
                                if (bh->b_page != bd_page) {
                                        end_page_writeback(bd_page);
@@ -1755,6 +1760,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
                                    b_assoc_buffers) {
                        set_buffer_uptodate(bh);
                        clear_buffer_dirty(bh);
+                       clear_buffer_async_write(bh);
                        if (bh->b_page != bd_page) {
                                if (bd_page)
                                        end_page_writeback(bd_page);
@@ -1776,6 +1782,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
                                    b_assoc_buffers) {
                        set_buffer_uptodate(bh);
                        clear_buffer_dirty(bh);
+                       clear_buffer_async_write(bh);
                        clear_buffer_delay(bh);
                        clear_buffer_nilfs_volatile(bh);
                        clear_buffer_nilfs_redirected(bh);
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 ef999729e274ead1ed88c699ee86b8011fd5ff77..0d3a97d2d5f659caeb60f20f448ce25371036ff2 100644 (file)
@@ -70,9 +70,10 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry, unsigned int flags)
         */
        if (inode == NULL) {
                unsigned long gen = (unsigned long) dentry->d_fsdata;
-               unsigned long pgen =
-                       OCFS2_I(dentry->d_parent->d_inode)->ip_dir_lock_gen;
-
+               unsigned long pgen;
+               spin_lock(&dentry->d_lock);
+               pgen = OCFS2_I(dentry->d_parent->d_inode)->ip_dir_lock_gen;
+               spin_unlock(&dentry->d_lock);
                trace_ocfs2_dentry_revalidate_negative(dentry->d_name.len,
                                                       dentry->d_name.name,
                                                       pgen, gen);
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 121da2dc3be841e579dd64fdea6bcfb89f5c121c..d4e81e4a9b0489de2eb66899eb23b9d87ea81ae5 100644 (file)
@@ -1924,7 +1924,7 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
 {
        int tmp, hangup_needed = 0;
        struct ocfs2_super *osb = NULL;
-       char nodestr[8];
+       char nodestr[12];
 
        trace_ocfs2_dismount_volume(sb);
 
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 e5c7f15465b49c2b744fe4fca30e107fa1d1ddae..19f134e896a9a8bdd69a387015819e4ebc3c2705 100644 (file)
@@ -32,7 +32,7 @@ enum ocfs2_xattr_type {
 
 struct ocfs2_security_xattr_info {
        int enable;
-       char *name;
+       const char *name;
        void *value;
        size_t value_len;
 };
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 8070825b285b93ae6120622eb315d673858e3ce0..d420331ca32a20b20b00c1da468a9af516e6a037 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -443,7 +443,7 @@ retry:
                goto dput_and_out;
 
        error = -EPERM;
-       if (!nsown_capable(CAP_SYS_CHROOT))
+       if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT))
                goto dput_and_out;
        error = security_path_chroot(&path);
        if (error)
@@ -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 b091445c1c4ac4472c09adb54496f7af98060a42..59e7eda1851ec447d705a02866c19a07d91d2c99 100644 (file)
 
 #define CL_EXPIRE              0x01
 #define CL_SLAVE               0x02
-#define CL_COPY_ALL            0x04
+#define CL_COPY_UNBINDABLE     0x04
 #define CL_MAKE_SHARED                 0x08
 #define CL_PRIVATE             0x10
 #define CL_SHARED_TO_SLAVE     0x20
 #define CL_UNPRIVILEGED                0x40
+#define CL_COPY_MNT_NS_FILE    0x80
+
+#define CL_COPY_ALL            (CL_COPY_UNBINDABLE | CL_COPY_MNT_NS_FILE)
 
 static inline void set_mnt_shared(struct mount *mnt)
 {
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 9f8ef9b7674db1ca1004b682b40a6e5500dcfc24..8eaa1ba793fc188879d405e768a81aedbaa4bf76 100644 (file)
@@ -288,10 +288,14 @@ static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma)
 static unsigned long proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 {
        struct proc_dir_entry *pde = PDE(file_inode(file));
-       int rv = -EIO;
-       unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+       unsigned long rv = -EIO;
+       unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long) = NULL;
        if (use_pde(pde)) {
-               get_unmapped_area = pde->proc_fops->get_unmapped_area;
+#ifdef CONFIG_MMU
+               get_unmapped_area = current->mm->get_unmapped_area;
+#endif
+               if (pde->proc_fops->get_unmapped_area)
+                       get_unmapped_area = pde->proc_fops->get_unmapped_area;
                if (get_unmapped_area)
                        rv = get_unmapped_area(file, orig_addr, len, pgoff, flags);
                unuse_pde(pde);
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 e0a790da726d0f710a7585b0a8b6663e9902a0ac..87dbcbef7fe4b3535d4bfdcbc7590af24d3d5f0a 100644 (file)
@@ -110,7 +110,11 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
                ns = task_active_pid_ns(current);
                options = data;
 
-               if (!current_user_ns()->may_mount_proc)
+               if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
+                       return ERR_PTR(-EPERM);
+
+               /* Does the mounter have privilege over the pid namespace? */
+               if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
                        return ERR_PTR(-EPERM);
        }
 
index 107d026f5d6e0cbebc068fce65f201f167c425c5..390bdab01c3c782cc14b55c6d1ef35ebddcc4197 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
 }
@@ -938,6 +941,8 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
                frame = pte_pfn(pte);
                flags = PM_PRESENT;
                page = vm_normal_page(vma, addr, pte);
+               if (pte_soft_dirty(pte))
+                       flags2 |= __PM_SOFT_DIRTY;
        } else if (is_swap_pte(pte)) {
                swp_entry_t entry;
                if (pte_swp_soft_dirty(pte))
@@ -949,13 +954,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))
                flags2 |= __PM_SOFT_DIRTY;
 
        *pme = make_pme(PM_PFRAME(frame) | PM_STATUS2(pm->v2, flags2) | flags);
@@ -974,7 +981,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 +1004,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 +1026,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 +1060,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 +1077,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 +1404,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 73feacc49b2ef3bc2b088f7d74ed05d4195a45ac..fd777032c2ba7551dd10fbf9572289b36d09ad27 100644 (file)
@@ -1163,21 +1163,6 @@ static struct reiserfs_journal_list *find_newer_jl_for_cn(struct
        return NULL;
 }
 
-static int newer_jl_done(struct reiserfs_journal_cnode *cn)
-{
-       struct super_block *sb = cn->sb;
-       b_blocknr_t blocknr = cn->blocknr;
-
-       cn = cn->hprev;
-       while (cn) {
-               if (cn->sb == sb && cn->blocknr == blocknr && cn->jlist &&
-                   atomic_read(&cn->jlist->j_commit_left) != 0)
-                                   return 0;
-               cn = cn->hprev;
-       }
-       return 1;
-}
-
 static void remove_journal_hash(struct super_block *,
                                struct reiserfs_journal_cnode **,
                                struct reiserfs_journal_list *, unsigned long,
@@ -1353,7 +1338,6 @@ static int flush_journal_list(struct super_block *s,
                reiserfs_warning(s, "clm-2048", "called with wcount %d",
                                 atomic_read(&journal->j_wcount));
        }
-       BUG_ON(jl->j_trans_id == 0);
 
        /* if flushall == 0, the lock is already held */
        if (flushall) {
@@ -1593,31 +1577,6 @@ static int flush_journal_list(struct super_block *s,
        return err;
 }
 
-static int test_transaction(struct super_block *s,
-                            struct reiserfs_journal_list *jl)
-{
-       struct reiserfs_journal_cnode *cn;
-
-       if (jl->j_len == 0 || atomic_read(&jl->j_nonzerolen) == 0)
-               return 1;
-
-       cn = jl->j_realblock;
-       while (cn) {
-               /* if the blocknr == 0, this has been cleared from the hash,
-                ** skip it
-                */
-               if (cn->blocknr == 0) {
-                       goto next;
-               }
-               if (cn->bh && !newer_jl_done(cn))
-                       return 0;
-             next:
-               cn = cn->next;
-               cond_resched();
-       }
-       return 0;
-}
-
 static int write_one_transaction(struct super_block *s,
                                 struct reiserfs_journal_list *jl,
                                 struct buffer_chunk *chunk)
@@ -1805,6 +1764,8 @@ static int flush_used_journal_lists(struct super_block *s,
                        break;
                tjl = JOURNAL_LIST_ENTRY(tjl->j_list.next);
        }
+       get_journal_list(jl);
+       get_journal_list(flush_jl);
        /* try to find a group of blocks we can flush across all the
         ** transactions, but only bother if we've actually spanned
         ** across multiple lists
@@ -1813,6 +1774,8 @@ static int flush_used_journal_lists(struct super_block *s,
                ret = kupdate_transactions(s, jl, &tjl, &trans_id, len, i);
        }
        flush_journal_list(s, flush_jl, 1);
+       put_journal_list(s, flush_jl);
+       put_journal_list(s, jl);
        return 0;
 }
 
@@ -3868,27 +3831,6 @@ int reiserfs_prepare_for_journal(struct super_block *sb,
        return 1;
 }
 
-static void flush_old_journal_lists(struct super_block *s)
-{
-       struct reiserfs_journal *journal = SB_JOURNAL(s);
-       struct reiserfs_journal_list *jl;
-       struct list_head *entry;
-       time_t now = get_seconds();
-
-       while (!list_empty(&journal->j_journal_list)) {
-               entry = journal->j_journal_list.next;
-               jl = JOURNAL_LIST_ENTRY(entry);
-               /* this check should always be run, to send old lists to disk */
-               if (jl->j_timestamp < (now - (JOURNAL_MAX_TRANS_AGE * 4)) &&
-                   atomic_read(&jl->j_commit_left) == 0 &&
-                   test_transaction(s, jl)) {
-                       flush_used_journal_lists(s, jl);
-               } else {
-                       break;
-               }
-       }
-}
-
 /*
 ** long and ugly.  If flush, will not return until all commit
 ** blocks and all real buffers in the trans are on disk.
@@ -4232,7 +4174,6 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
                        }
                }
        }
-       flush_old_journal_lists(sb);
 
        journal->j_current_jl->j_list_bitmap =
            get_list_bitmap(sb, journal->j_current_jl);
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 c219e733f55330741962173e994ac8d4e894a70f..083dc0ac91408870254cac60ed4b06580deba610 100644 (file)
@@ -94,7 +94,7 @@ retry:
 
 int fd_statfs(int fd, struct kstatfs *st)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_raw(fd);
        int error = -EBADF;
        if (f.file) {
                error = vfs_statfs(&f.file->f_path, st);
index 5536a95186e28cc60d27676714cc5bb8a1ec350b..0225c20f877047abb0a47a856c6099594964b6aa 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
@@ -236,6 +264,8 @@ out_free_sb:
  */
 static inline void destroy_super(struct super_block *s)
 {
+       list_lru_destroy(&s->s_dentry_lru);
+       list_lru_destroy(&s->s_inode_lru);
 #ifdef CONFIG_SMP
        free_percpu(s->s_files);
 #endif
@@ -295,6 +325,7 @@ void deactivate_locked_super(struct super_block *s)
 
                /* caches are now gone, we can safely kill the shrinker now */
                unregister_shrinker(&s->s_shrink);
+
                put_filesystem(fs);
                put_super(s);
        } else {
index 99ec5b40e977730a3613ff295740446e651fba42..4d83cedb9fcb6a98b784bb7e5d67472b9e96e289 100644 (file)
@@ -297,7 +297,6 @@ static int sysfs_dentry_delete(const struct dentry *dentry)
 static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct sysfs_dirent *sd;
-       int is_dir;
        int type;
 
        if (flags & LOOKUP_RCU)
@@ -341,18 +340,15 @@ out_bad:
         * is performed at its new name the dentry will be readded
         * to the dcache hashes.
         */
-       is_dir = (sysfs_type(sd) == SYSFS_DIR);
        mutex_unlock(&sysfs_mutex);
-       if (is_dir) {
-               /* If we have submounts we must allow the vfs caches
-                * to lie about the state of the filesystem to prevent
-                * leaks and other nasty things.
-                */
-               if (have_submounts(dentry))
-                       goto out_valid;
-               shrink_dcache_parent(dentry);
-       }
-       d_drop(dentry);
+
+       /* If we have submounts we must allow the vfs caches
+        * to lie about the state of the filesystem to prevent
+        * leaks and other nasty things.
+        */
+       if (check_submounts_and_drop(dentry) != 0)
+               goto out_valid;
+
        return 0;
 }
 
index fd7ce7a39f91acfa9304fd80e9ff5a6e7e1139cc..834ec2cdb7a37e070b7e5ed04ec684ba46cb2093 100644 (file)
@@ -112,8 +112,15 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
        struct super_block *sb;
        int error;
 
-       if (!(flags & MS_KERNMOUNT) && !current_user_ns()->may_mount_sysfs)
-               return ERR_PTR(-EPERM);
+       if (!(flags & MS_KERNMOUNT)) {
+               if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
+                       return ERR_PTR(-EPERM);
+
+               for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) {
+                       if (!kobj_ns_current_may_mount(type))
+                               return ERR_PTR(-EPERM);
+               }
+       }
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info)
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 d0c6a007ce835cf869fac695eb5445b34be6d814..eda10959714f2acad6ce5d9be82fffbe9426513b 100644 (file)
@@ -487,6 +487,7 @@ static int v7_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_sb = sb;
        sbi->s_block_base = 0;
        sbi->s_type = FSTYPE_V7;
+       mutex_init(&sbi->s_lock);
        sb->s_fs_info = sbi;
        
        sb_set_blocksize(sb, 512);
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 7e5aae4bf46fd1c1e65da56615238ffe4944fd3b..6eaf5edf1ea1577e88cafc60184963e1b18df5a5 100644 (file)
@@ -30,18 +30,17 @@ void udf_free_inode(struct inode *inode)
 {
        struct super_block *sb = inode->i_sb;
        struct udf_sb_info *sbi = UDF_SB(sb);
+       struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb);
 
-       mutex_lock(&sbi->s_alloc_mutex);
-       if (sbi->s_lvid_bh) {
-               struct logicalVolIntegrityDescImpUse *lvidiu =
-                                                       udf_sb_lvidiu(sbi);
+       if (lvidiu) {
+               mutex_lock(&sbi->s_alloc_mutex);
                if (S_ISDIR(inode->i_mode))
                        le32_add_cpu(&lvidiu->numDirs, -1);
                else
                        le32_add_cpu(&lvidiu->numFiles, -1);
                udf_updated_lvid(sb);
+               mutex_unlock(&sbi->s_alloc_mutex);
        }
-       mutex_unlock(&sbi->s_alloc_mutex);
 
        udf_free_blocks(sb, NULL, &UDF_I(inode)->i_location, 0, 1);
 }
@@ -55,6 +54,7 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode, int *err)
        uint32_t start = UDF_I(dir)->i_location.logicalBlockNum;
        struct udf_inode_info *iinfo;
        struct udf_inode_info *dinfo = UDF_I(dir);
+       struct logicalVolIntegrityDescImpUse *lvidiu;
 
        inode = new_inode(sb);
 
@@ -92,12 +92,10 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode, int *err)
                return NULL;
        }
 
-       if (sbi->s_lvid_bh) {
-               struct logicalVolIntegrityDescImpUse *lvidiu;
-
+       lvidiu = udf_sb_lvidiu(sb);
+       if (lvidiu) {
                iinfo->i_unique = lvid_get_unique_id(sb);
                mutex_lock(&sbi->s_alloc_mutex);
-               lvidiu = udf_sb_lvidiu(sbi);
                if (S_ISDIR(mode))
                        le32_add_cpu(&lvidiu->numDirs, 1);
                else
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 839a2bad7f45b693db4ed478598b997c42077712..91219385691d8f80d1db9aed3973183bb931a48d 100644 (file)
@@ -94,13 +94,25 @@ static unsigned int udf_count_free(struct super_block *);
 static int udf_statfs(struct dentry *, struct kstatfs *);
 static int udf_show_options(struct seq_file *, struct dentry *);
 
-struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi)
+struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb)
 {
-       struct logicalVolIntegrityDesc *lvid =
-               (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data;
-       __u32 number_of_partitions = le32_to_cpu(lvid->numOfPartitions);
-       __u32 offset = number_of_partitions * 2 *
-                               sizeof(uint32_t)/sizeof(uint8_t);
+       struct logicalVolIntegrityDesc *lvid;
+       unsigned int partnum;
+       unsigned int offset;
+
+       if (!UDF_SB(sb)->s_lvid_bh)
+               return NULL;
+       lvid = (struct logicalVolIntegrityDesc *)UDF_SB(sb)->s_lvid_bh->b_data;
+       partnum = le32_to_cpu(lvid->numOfPartitions);
+       if ((sb->s_blocksize - sizeof(struct logicalVolIntegrityDescImpUse) -
+            offsetof(struct logicalVolIntegrityDesc, impUse)) /
+            (2 * sizeof(uint32_t)) < partnum) {
+               udf_err(sb, "Logical volume integrity descriptor corrupted "
+                       "(numOfPartitions = %u)!\n", partnum);
+               return NULL;
+       }
+       /* The offset is to skip freeSpaceTable and sizeTable arrays */
+       offset = partnum * 2 * sizeof(uint32_t);
        return (struct logicalVolIntegrityDescImpUse *)&(lvid->impUse[offset]);
 }
 
@@ -629,9 +641,10 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
        struct udf_options uopt;
        struct udf_sb_info *sbi = UDF_SB(sb);
        int error = 0;
+       struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb);
 
-       if (sbi->s_lvid_bh) {
-               int write_rev = le16_to_cpu(udf_sb_lvidiu(sbi)->minUDFWriteRev);
+       if (lvidiu) {
+               int write_rev = le16_to_cpu(lvidiu->minUDFWriteRev);
                if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & MS_RDONLY))
                        return -EACCES;
        }
@@ -1905,11 +1918,12 @@ static void udf_open_lvid(struct super_block *sb)
 
        if (!bh)
                return;
-
-       mutex_lock(&sbi->s_alloc_mutex);
        lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
-       lvidiu = udf_sb_lvidiu(sbi);
+       lvidiu = udf_sb_lvidiu(sb);
+       if (!lvidiu)
+               return;
 
+       mutex_lock(&sbi->s_alloc_mutex);
        lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
        lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
        udf_time_to_disk_stamp(&lvid->recordingDateAndTime,
@@ -1937,10 +1951,12 @@ static void udf_close_lvid(struct super_block *sb)
 
        if (!bh)
                return;
+       lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
+       lvidiu = udf_sb_lvidiu(sb);
+       if (!lvidiu)
+               return;
 
        mutex_lock(&sbi->s_alloc_mutex);
-       lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
-       lvidiu = udf_sb_lvidiu(sbi);
        lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
        lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
        udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME);
@@ -2093,15 +2109,19 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
 
        if (sbi->s_lvid_bh) {
                struct logicalVolIntegrityDescImpUse *lvidiu =
-                                                       udf_sb_lvidiu(sbi);
-               uint16_t minUDFReadRev = le16_to_cpu(lvidiu->minUDFReadRev);
-               uint16_t minUDFWriteRev = le16_to_cpu(lvidiu->minUDFWriteRev);
-               /* uint16_t maxUDFWriteRev =
-                               le16_to_cpu(lvidiu->maxUDFWriteRev); */
+                                                       udf_sb_lvidiu(sb);
+               uint16_t minUDFReadRev;
+               uint16_t minUDFWriteRev;
 
+               if (!lvidiu) {
+                       ret = -EINVAL;
+                       goto error_out;
+               }
+               minUDFReadRev = le16_to_cpu(lvidiu->minUDFReadRev);
+               minUDFWriteRev = le16_to_cpu(lvidiu->minUDFWriteRev);
                if (minUDFReadRev > UDF_MAX_READ_VERSION) {
                        udf_err(sb, "minUDFReadRev=%x (max is %x)\n",
-                               le16_to_cpu(lvidiu->minUDFReadRev),
+                               minUDFReadRev,
                                UDF_MAX_READ_VERSION);
                        ret = -EINVAL;
                        goto error_out;
@@ -2265,11 +2285,7 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct logicalVolIntegrityDescImpUse *lvidiu;
        u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
-       if (sbi->s_lvid_bh != NULL)
-               lvidiu = udf_sb_lvidiu(sbi);
-       else
-               lvidiu = NULL;
-
+       lvidiu = udf_sb_lvidiu(sb);
        buf->f_type = UDF_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
        buf->f_blocks = sbi->s_partmaps[sbi->s_partition].s_partition_len;
index ed401e94aa8c956dd8685ab33f496fc4ea52eec7..1f32c7bd9f57f21fb2859413cacde08b2949fd3a 100644 (file)
@@ -162,7 +162,7 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
        return sb->s_fs_info;
 }
 
-struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi);
+struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb);
 
 int udf_compute_nr_groups(struct super_block *sb, u32 partition);
 
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..f1d85cfc0a54d1cb54ebe95937872127f2e63142 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,28 @@ 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) {
+                               spin_lock(&lip->li_ailp->xa_lock);
+                               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..20bf8e8002d6fd2733782af97f373ddaf2bcd8d6 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;
 
@@ -1223,6 +1224,7 @@ xfs_da3_node_toosmall(
        /* start with smaller blk num */
        forward = nodehdr.forw < nodehdr.back;
        for (i = 0; i < 2; forward = !forward, i++) {
+               struct xfs_da3_icnode_hdr thdr;
                if (forward)
                        blkno = nodehdr.forw;
                else
@@ -1235,10 +1237,10 @@ xfs_da3_node_toosmall(
                        return(error);
 
                node = bp->b_addr;
-               xfs_da3_node_hdr_from_disk(&nodehdr, node);
+               xfs_da3_node_hdr_from_disk(&thdr, node);
                xfs_trans_brelse(state->args->trans, bp);
 
-               if (count - nodehdr.count >= 0)
+               if (count - thdr.count >= 0)
                        break;  /* fits with at least 25% to spare */
        }
        if (i >= 2) {
@@ -2454,9 +2456,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..12dad188939df2e29c4420574bd20bfb319aae35 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;
@@ -1250,11 +1158,12 @@ xfs_dir2_sf_to_block(
        /*
         * Create entry for .
         */
-       dep = xfs_dir3_data_dot_entry_p(hdr);
+       dep = xfs_dir3_data_dot_entry_p(mp, hdr);
        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);
@@ -1263,17 +1172,18 @@ xfs_dir2_sf_to_block(
        /*
         * Create entry for ..
         */
-       dep = xfs_dir3_data_dotdot_entry_p(hdr);
+       dep = xfs_dir3_data_dotdot_entry_p(mp, hdr);
        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);
        blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
                                (char *)dep - (char *)hdr));
-       offset = xfs_dir3_data_first_offset(hdr);
+       offset = xfs_dir3_data_first_offset(mp);
        /*
         * Loop over existing entries, stuff them in.
         */
@@ -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..9cf67381adf6769d0b6fc984b6fe5ecaf8cef5b4 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)
+{
+       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)
 {
-       return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n +
-                (uint)sizeof(xfs_dir2_data_off_t), XFS_DIR2_DATA_ALIGN);
+       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));
 }
 
 /*
@@ -370,59 +497,58 @@ xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr)
 /*
  * Offsets of . and .. in data space (always block 0)
  *
- * The macros are used for shortform directories as they have no headers to read
- * the magic number out of. Shortform directories need to know the size of the
- * 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.
- */
-#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))
-#define        XFS_DIR3_DATA_FIRST_OFFSET(mp)          \
-       (XFS_DIR3_DATA_DOTDOT_OFFSET(mp) + xfs_dir2_data_entsize(2))
-
+ * 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.
+ */
 static inline xfs_dir2_data_aoff_t
-xfs_dir3_data_dot_offset(struct xfs_dir2_data_hdr *hdr)
+xfs_dir3_data_dot_offset(struct xfs_mount *mp)
 {
-       return xfs_dir3_data_entry_offset(hdr);
+       return xfs_dir3_data_hdr_size(xfs_sb_version_hascrc(&mp->m_sb));
 }
 
 static inline xfs_dir2_data_aoff_t
-xfs_dir3_data_dotdot_offset(struct xfs_dir2_data_hdr *hdr)
+xfs_dir3_data_dotdot_offset(struct xfs_mount *mp)
 {
-       return xfs_dir3_data_dot_offset(hdr) + xfs_dir2_data_entsize(1);
+       return xfs_dir3_data_dot_offset(mp) +
+               xfs_dir3_data_entsize(mp, 1);
 }
 
 static inline xfs_dir2_data_aoff_t
-xfs_dir3_data_first_offset(struct xfs_dir2_data_hdr *hdr)
+xfs_dir3_data_first_offset(struct xfs_mount *mp)
 {
-       return xfs_dir3_data_dotdot_offset(hdr) + xfs_dir2_data_entsize(2);
+       return xfs_dir3_data_dotdot_offset(mp) +
+               xfs_dir3_data_entsize(mp, 2);
 }
 
 /*
  * location of . and .. in data space (always block 0)
  */
 static inline struct xfs_dir2_data_entry *
-xfs_dir3_data_dot_entry_p(struct xfs_dir2_data_hdr *hdr)
+xfs_dir3_data_dot_entry_p(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_data_hdr *hdr)
 {
        return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + xfs_dir3_data_dot_offset(hdr));
+               ((char *)hdr + xfs_dir3_data_dot_offset(mp));
 }
 
 static inline struct xfs_dir2_data_entry *
-xfs_dir3_data_dotdot_entry_p(struct xfs_dir2_data_hdr *hdr)
+xfs_dir3_data_dotdot_entry_p(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_data_hdr *hdr)
 {
        return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + xfs_dir3_data_dotdot_offset(hdr));
+               ((char *)hdr + xfs_dir3_data_dotdot_offset(mp));
 }
 
 static inline struct xfs_dir2_data_entry *
-xfs_dir3_data_first_entry_p(struct xfs_dir2_data_hdr *hdr)
+xfs_dir3_data_first_entry_p(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_data_hdr *hdr)
 {
        return (struct xfs_dir2_data_entry *)
-               ((char *)hdr + xfs_dir3_data_first_offset(hdr));
+               ((char *)hdr + xfs_dir3_data_first_offset(mp));
 }
 
 /*
@@ -519,6 +645,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..8f84153
--- /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..3ef6d402084ccf9dabc622ee5db22b41170e3e54 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,8 +639,8 @@ 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);
-       offset = XFS_DIR3_DATA_FIRST_OFFSET(mp);
+       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..1ee776d477c3d1b240378993f946e9716f62c83d 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"
@@ -62,7 +64,8 @@ int xfs_dqerror_mod = 33;
 struct kmem_zone               *xfs_qm_dqtrxzone;
 static struct kmem_zone                *xfs_qm_dqzone;
 
-static struct lock_class_key xfs_dquot_other_class;
+static struct lock_class_key xfs_dquot_group_class;
+static struct lock_class_key xfs_dquot_project_class;
 
 /*
  * This is called to free all the memory associated with a dquot
@@ -701,8 +704,20 @@ xfs_qm_dqread(
         * Make sure group quotas have a different lock class than user
         * quotas.
         */
-       if (!(type & XFS_DQ_USER))
-               lockdep_set_class(&dqp->q_qlock, &xfs_dquot_other_class);
+       switch (type) {
+       case XFS_DQ_USER:
+               /* uses the default lock class */
+               break;
+       case XFS_DQ_GROUP:
+               lockdep_set_class(&dqp->q_qlock, &xfs_dquot_group_class);
+               break;
+       case XFS_DQ_PROJ:
+               lockdep_set_class(&dqp->q_qlock, &xfs_dquot_project_class);
+               break;
+       default:
+               ASSERT(0);
+               break;
+       }
 
        XFS_STATS_INC(xs_qm_dquot);
 
@@ -710,10 +725,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 +953,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..18272c766a508ab53deb5465448ca26bf02110d6 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
  */
@@ -487,7 +515,7 @@ typedef struct xfs_handle {
 /*     XFS_IOC_GETBIOSIZE ---- deprecated 47      */
 #define XFS_IOC_GETBMAPX       _IOWR('X', 56, struct getbmap)
 #define XFS_IOC_ZERO_RANGE     _IOW ('X', 57, struct xfs_flock64)
-#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_eofblocks)
+#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks)
 
 /*
  * ioctl commands that replace IRIX syssgi()'s
@@ -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..474807a401c864e7681d3f8d0f111358c45536fc 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)
 {
@@ -118,11 +119,6 @@ xfs_inode_free(
                ip->i_itemp = NULL;
        }
 
-       /* asserts to verify all state is correct here */
-       ASSERT(atomic_read(&ip->i_pincount) == 0);
-       ASSERT(!spin_is_locked(&ip->i_flags_lock));
-       ASSERT(!xfs_isiflocked(ip));
-
        /*
         * Because we use RCU freeing we need to ensure the inode always
         * appears to be reclaimed with an invalid inode number when in the
@@ -134,6 +130,10 @@ xfs_inode_free(
        ip->i_ino = 0;
        spin_unlock(&ip->i_flags_lock);
 
+       /* asserts to verify all state is correct here */
+       ASSERT(atomic_read(&ip->i_pincount) == 0);
+       ASSERT(!xfs_isiflocked(ip));
+
        call_rcu(&VFS_I(ip)->i_rcu, xfs_inode_free_callback);
 }
 
@@ -619,7 +619,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 +1166,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 +1175,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 +1203,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..39797490a1f1996e3f92f51efb532f15a75da8fa 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 */
@@ -1582,6 +1585,7 @@ xlog_recover_add_to_trans(
                "bad number of regions (%d) in inode log format",
                                  in_f->ilf_size);
                        ASSERT(0);
+                       kmem_free(ptr);
                        return XFS_ERROR(EIO);
                }
 
@@ -1766,19 +1770,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 +1783,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 +1800,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 +1959,149 @@ 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.
+ *
+ * Note: we cannot rely solely on magic number matches to determine that the
+ * buffer has a valid LSN - we also need to verify that it belongs to this
+ * filesystem, so we need to extract the object's LSN and compare it to that
+ * which we read from the superblock. If the UUIDs don't match, then we've got a
+ * stale metadata block from an old filesystem instance that we need to recover
+ * over the top of.
+ */
+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;
+       uuid_t                  *uuid;
+       xfs_lsn_t               lsn = -1;
+
+       /* 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: {
+               struct xfs_btree_block *btb = blk;
+
+               lsn = be64_to_cpu(btb->bb_u.s.bb_lsn);
+               uuid = &btb->bb_u.s.bb_uuid;
+               break;
+       }
+       case XFS_BMAP_CRC_MAGIC:
+       case XFS_BMAP_MAGIC: {
+               struct xfs_btree_block *btb = blk;
+
+               lsn = be64_to_cpu(btb->bb_u.l.bb_lsn);
+               uuid = &btb->bb_u.l.bb_uuid;
+               break;
+       }
+       case XFS_AGF_MAGIC:
+               lsn = be64_to_cpu(((struct xfs_agf *)blk)->agf_lsn);
+               uuid = &((struct xfs_agf *)blk)->agf_uuid;
+               break;
+       case XFS_AGFL_MAGIC:
+               lsn = be64_to_cpu(((struct xfs_agfl *)blk)->agfl_lsn);
+               uuid = &((struct xfs_agfl *)blk)->agfl_uuid;
+               break;
+       case XFS_AGI_MAGIC:
+               lsn = be64_to_cpu(((struct xfs_agi *)blk)->agi_lsn);
+               uuid = &((struct xfs_agi *)blk)->agi_uuid;
+               break;
+       case XFS_SYMLINK_MAGIC:
+               lsn = be64_to_cpu(((struct xfs_dsymlink_hdr *)blk)->sl_lsn);
+               uuid = &((struct xfs_dsymlink_hdr *)blk)->sl_uuid;
+               break;
+       case XFS_DIR3_BLOCK_MAGIC:
+       case XFS_DIR3_DATA_MAGIC:
+       case XFS_DIR3_FREE_MAGIC:
+               lsn = be64_to_cpu(((struct xfs_dir3_blk_hdr *)blk)->lsn);
+               uuid = &((struct xfs_dir3_blk_hdr *)blk)->uuid;
+               break;
+       case XFS_ATTR3_RMT_MAGIC:
+               lsn = be64_to_cpu(((struct xfs_attr3_rmt_hdr *)blk)->rm_lsn);
+               uuid = &((struct xfs_attr3_rmt_hdr *)blk)->rm_uuid;
+               break;
+       case XFS_SB_MAGIC:
+               lsn = be64_to_cpu(((struct xfs_dsb *)blk)->sb_lsn);
+               uuid = &((struct xfs_dsb *)blk)->sb_uuid;
+               break;
+       default:
+               break;
+       }
+
+       if (lsn != (xfs_lsn_t)-1) {
+               if (!uuid_equal(&mp->m_sb.sb_uuid, uuid))
+                       goto recover_immediately;
+               return lsn;
+       }
+
+       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:
+               lsn = be64_to_cpu(((struct xfs_da3_blkinfo *)blk)->lsn);
+               uuid = &((struct xfs_da3_blkinfo *)blk)->uuid;
+               break;
+       default:
+               break;
+       }
+
+       if (lsn != (xfs_lsn_t)-1) {
+               if (!uuid_equal(&mp->m_sb.sb_uuid, uuid))
+                       goto recover_immediately;
+               return lsn;
+       }
+
+       /*
+        * 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 +2111,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 +2390,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 +2522,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 +2581,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 +2621,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 +2641,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 +2670,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 +2803,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 +2813,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 +2867,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 +2881,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 +2894,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 +2912,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 +2958,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 +3019,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 +3077,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 +3152,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 +3175,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 +3386,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 +3525,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 +3550,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 +3582,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 +3599,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 +3624,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 +3794,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 +3900,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>
index 02e113bb8b7d5c777fdc435a5285208238ce66e9..d9019821aa6020e1c6d974856edfb404cb81d8c8 100644 (file)
@@ -311,7 +311,6 @@ struct acpi_device {
        unsigned int physical_node_count;
        struct list_head physical_node_list;
        struct mutex physical_node_lock;
-       struct list_head power_dependent;
        void (*remove)(struct acpi_device *);
 };
 
@@ -456,8 +455,6 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
 acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
                                    acpi_notify_handler handler);
 int acpi_pm_device_sleep_state(struct device *, int *, int);
-void acpi_dev_pm_add_dependent(acpi_handle handle, struct device *depdev);
-void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev);
 #else
 static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
                                               acpi_notify_handler handler,
@@ -478,10 +475,6 @@ static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m)
        return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3_COLD) ?
                m : ACPI_STATE_D0;
 }
-static inline void acpi_dev_pm_add_dependent(acpi_handle handle,
-                                            struct device *depdev) {}
-static inline void acpi_dev_pm_remove_dependent(acpi_handle handle,
-                                               struct device *depdev) {}
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
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 d06079c774a081e5a5f467da8cb4680c9d23054e..99b490b4d05aa5cff749937f3a3a69a5c3406f92 100644 (file)
@@ -6,12 +6,12 @@ static inline pte_t mk_huge_pte(struct page *page, pgprot_t pgprot)
        return mk_pte(page, pgprot);
 }
 
-static inline int huge_pte_write(pte_t pte)
+static inline unsigned long huge_pte_write(pte_t pte)
 {
        return pte_write(pte);
 }
 
-static inline int huge_pte_dirty(pte_t pte)
+static inline unsigned long huge_pte_dirty(pte_t pte)
 {
        return pte_dirty(pte);
 }
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b1a49677fe2540e93aae3b40b1c235949ac756cf 100644 (file)
@@ -0,0 +1 @@
+/* no content, but patch(1) dislikes empty files */
index 3744d2a642dfbdf8a13141f0e2491b372a1d7a55..13621cc8cf4c454f546a6fbb33fb5e85e8b1b1aa 100644 (file)
@@ -113,4 +113,6 @@ void scatterwalk_done(struct scatter_walk *walk, int out, int more);
 void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
                              unsigned int start, unsigned int nbytes, int out);
 
+int scatterwalk_bytes_sglen(struct scatterlist *sg, int num_bytes);
+
 #endif  /* _CRYPTO_SCATTERWALK_H */
index 290734191f72d85a855022a2f0e24e7a6c895ffb..b46fb45f2cca4a5881b64d93577e6ae03a221670 100644 (file)
@@ -1322,10 +1322,9 @@ extern int drm_newctx(struct drm_device *dev, void *data,
 extern int drm_rmctx(struct drm_device *dev, void *data,
                     struct drm_file *file_priv);
 
-extern void drm_legacy_ctxbitmap_init(struct drm_device *dev);
-extern void drm_legacy_ctxbitmap_cleanup(struct drm_device *dev);
-extern void drm_legacy_ctxbitmap_release(struct drm_device *dev,
-                                        struct drm_file *file_priv);
+extern int drm_ctxbitmap_init(struct drm_device *dev);
+extern void drm_ctxbitmap_cleanup(struct drm_device *dev);
+extern void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle);
 
 extern int drm_setsareactx(struct drm_device *dev, void *data,
                           struct drm_file *file_priv);
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 edbd250809cb6d415e893a2d26a9d6db302925fd..bed35e36fd2748515ed75f47c9d642462223c852 100644 (file)
@@ -23,7 +23,7 @@
 #define PULL_UP                        (1 << 4)
 #define ALTELECTRICALSEL       (1 << 5)
 
-/* 34xx specific mux bit defines */
+/* omap3/4/5 specific mux bit defines */
 #define INPUT_EN               (1 << 8)
 #define OFF_EN                 (1 << 9)
 #define OFFOUT_EN              (1 << 10)
@@ -31,8 +31,6 @@
 #define OFF_PULL_EN            (1 << 12)
 #define OFF_PULL_UP            (1 << 13)
 #define WAKEUP_EN              (1 << 14)
-
-/* 44xx specific mux bit defines */
 #define WAKEUP_EVENT           (1 << 15)
 
 /* Active pin states */
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 f7f1d7169b11c332612ba09a1663141870e08849..089743ade734fc564e18bfa7be35608da68d6fde 100644 (file)
@@ -158,6 +158,26 @@ static inline bool balloon_page_movable(struct page *page)
        return false;
 }
 
+/*
+ * isolated_balloon_page - identify an isolated balloon page on private
+ *                        compaction/migration page lists.
+ *
+ * After a compaction thread isolates a balloon page for migration, it raises
+ * the page refcount to prevent concurrent compaction threads from re-isolating
+ * the same page. For that reason putback_movable_pages(), or other routines
+ * that need to identify isolated balloon pages on private pagelists, cannot
+ * rely on balloon_page_movable() to accomplish the task.
+ */
+static inline bool isolated_balloon_page(struct page *page)
+{
+       /* Already isolated balloon pages, by default, have a raised refcount */
+       if (page_flags_cleared(page) && !page_mapped(page) &&
+           page_count(page) >= 2)
+               return __is_movable_balloon_page(page);
+
+       return false;
+}
+
 /*
  * balloon_page_insert - insert a page into the balloon's page list and make
  *                      the page->mapping assignment accordingly.
@@ -243,6 +263,11 @@ static inline bool balloon_page_movable(struct page *page)
        return false;
 }
 
+static inline bool isolated_balloon_page(struct page *page)
+{
+       return false;
+}
+
 static inline bool balloon_page_isolate(struct page *page)
 {
        return false;
index d66033f418c98bf1818ba2c5fcbdc7bcebe8021b..0333e605ea0d752c5aa306957a80aa72c5d4094f 100644 (file)
@@ -242,6 +242,7 @@ extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
                                 struct bcma_device *core, bool enable);
 extern void bcma_core_pci_up(struct bcma_bus *bus);
 extern void bcma_core_pci_down(struct bcma_bus *bus);
+extern void bcma_core_pci_power_save(struct bcma_bus *bus, bool up);
 
 extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
 extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);
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 2fdb4a451b49bd626d9415b231c76b7ac927cf69..0e6f765aa1f5adf3acbf54e27cea6fbe495de1cb 100644 (file)
@@ -862,6 +862,17 @@ static inline unsigned int blk_rq_get_max_sectors(struct request *rq)
        return blk_queue_get_max_sectors(q, rq->cmd_flags);
 }
 
+static inline unsigned int blk_rq_count_bios(struct request *rq)
+{
+       unsigned int nr_bios = 0;
+       struct bio *bio;
+
+       __rq_for_each_bio(bio, rq)
+               nr_bios++;
+
+       return nr_bios;
+}
+
 /*
  * Request issue related functions.
  */
index d9a4f7f40f329b22c81f86e31c72b259d4acb4bf..a6ee1f9a5018544294b50e27b6feac325db63af2 100644 (file)
@@ -210,7 +210,6 @@ extern bool has_ns_capability_noaudit(struct task_struct *t,
                                      struct user_namespace *ns, int cap);
 extern bool capable(int cap);
 extern bool ns_capable(struct user_namespace *ns, int cap);
-extern bool nsown_capable(int cap);
 extern bool inode_capable(const struct inode *inode, int cap);
 extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap);
 
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 842de225055fc5b8c769c59ff37e5afa81574f38..ded429966c1f447db9106359b174fb742fd3fe54 100644 (file)
 #define __visible __attribute__((externally_visible))
 #endif
 
+/*
+ * GCC 'asm goto' miscompiles certain code sequences:
+ *
+ *   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
+ *
+ * Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
+ * Fixed in GCC 4.8.2 and later versions.
+ *
+ * (asm goto is automatically volatile - the naming reflects this.)
+ */
+#if GCC_VERSION <= 40801
+# define asm_volatile_goto(x...)       do { asm goto(x); asm (""); } while (0)
+#else
+# define asm_volatile_goto(x...)       do { asm goto(x); } while (0)
+#endif
 
 #ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
 #if GCC_VERSION >= 40400
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 a9c96d865ee7144b577afc3752c0a1a94cd95e11..b3cb71f0d3b0d19b8c08e70348dee1bb5e5ba6ad 100644 (file)
@@ -3,6 +3,10 @@
 
 #include <linux/types.h>
 
+#define CRC_T10DIF_DIGEST_SIZE 2
+#define CRC_T10DIF_BLOCK_SIZE 1
+
+__u16 crc_t10dif_generic(__u16 crc, const unsigned char *buffer, size_t len);
 __u16 crc_t10dif(unsigned char const *, size_t);
 
 #endif
index 9169b91ea2d289e34952400b8ca89252222690e7..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,11 +208,12 @@ 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;
 
-static inline int dname_external(struct dentry *dentry)
+static inline int dname_external(const struct dentry *dentry)
 {
        return dentry->d_name.name != dentry->d_iname;
 }
@@ -253,6 +254,7 @@ extern void d_prune_aliases(struct inode *);
 
 /* test whether we have any submounts in a subdir tree */
 extern int have_submounts(struct dentry *);
+extern int check_submounts_and_drop(struct dentry *);
 
 /*
  * This adds the entry to the hash queues.
@@ -357,17 +359,17 @@ extern struct dentry *dget_parent(struct dentry *dentry);
  *     Returns true if the dentry passed is not currently hashed.
  */
  
-static inline int d_unhashed(struct dentry *dentry)
+static inline int d_unhashed(const struct dentry *dentry)
 {
        return hlist_bl_unhashed(&dentry->d_hash);
 }
 
-static inline int d_unlinked(struct dentry *dentry)
+static inline int d_unlinked(const struct dentry *dentry)
 {
        return d_unhashed(dentry) && !IS_ROOT(dentry);
 }
 
-static inline int cant_mount(struct dentry *dentry)
+static inline int cant_mount(const struct dentry *dentry)
 {
        return (dentry->d_flags & DCACHE_CANT_MOUNT);
 }
@@ -381,16 +383,20 @@ static inline void dont_mount(struct dentry *dentry)
 
 extern void dput(struct dentry *);
 
-static inline bool d_managed(struct dentry *dentry)
+static inline bool d_managed(const struct dentry *dentry)
 {
        return dentry->d_flags & DCACHE_MANAGED_DENTRY;
 }
 
-static inline bool d_mountpoint(struct dentry *dentry)
+static inline bool d_mountpoint(const struct dentry *dentry)
 {
        return dentry->d_flags & DCACHE_MOUNTED;
 }
 
 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..ed419c62dde1876f4561179b6b4bc3052a50ed14 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;
@@ -405,13 +406,14 @@ int dm_noflush_suspending(struct dm_target *ti);
 union map_info *dm_get_mapinfo(struct bio *bio);
 union map_info *dm_get_rq_mapinfo(struct request *rq);
 
+struct queue_limits *dm_get_queue_limits(struct mapped_device *md);
+
 /*
  * Geometry functions.
  */
 int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo);
 int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo);
 
-
 /*-----------------------------------------------------------------
  * Functions for manipulating device-mapper tables.
  *---------------------------------------------------------------*/
@@ -550,6 +552,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 3b4cd8296e4165625b11584b7f134a5587b0f23b..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);
 };
 
 /*
@@ -1900,6 +1895,7 @@ extern int vfs_ustat(dev_t, struct kstatfs *);
 extern int freeze_super(struct super_block *super);
 extern int thaw_super(struct super_block *super);
 extern bool our_mnt(struct vfsmount *mnt);
+extern bool fs_fully_visible(struct file_system_type *);
 
 extern int current_umask(void);
 
@@ -2073,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; }
@@ -2092,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;
@@ -2493,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 a3b8b2e2d24438129df020cc8d7af78562123cad..d98503bde7e9bc7ace0e2c3ddc5f2ae019f527ff 100644 (file)
 /*
  * Framework version for util services.
  */
+#define UTIL_FW_MINOR  0
+
+#define UTIL_WS2K8_FW_MAJOR  1
+#define UTIL_WS2K8_FW_VERSION     (UTIL_WS2K8_FW_MAJOR << 16 | UTIL_FW_MINOR)
 
 #define UTIL_FW_MAJOR  3
-#define UTIL_FW_MINOR  0
-#define UTIL_FW_MAJOR_MINOR     (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR)
+#define UTIL_FW_VERSION     (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR)
 
 
 /*
index a986ff588944ae0a5bb1ccc7017150324b488210..0f9bafa17a02dde9af7f4866ca8b9f741c83ddf1 100644 (file)
 #define I8042_CMD_MUX_PFX      0x0090
 #define I8042_CMD_MUX_SEND     0x1090
 
+/*
+ * Status register bits.
+ */
+
+#define I8042_STR_PARITY       0x80
+#define I8042_STR_TIMEOUT      0x40
+#define I8042_STR_AUXDATA      0x20
+#define I8042_STR_KEYLOCK      0x10
+#define I8042_STR_CMDDAT       0x08
+#define I8042_STR_MUXERR       0x04
+#define I8042_STR_IBF          0x02
+#define I8042_STR_OBF          0x01
+
+/*
+ * Control register bits.
+ */
+
+#define I8042_CTR_KBDINT       0x01
+#define I8042_CTR_AUXINT       0x02
+#define I8042_CTR_IGNKEYLOCK   0x08
+#define I8042_CTR_KBDDIS       0x10
+#define I8042_CTR_AUXDIS       0x20
+#define I8042_CTR_XLATE                0x40
+
 struct serio;
 
 #if defined(CONFIG_SERIO_I8042) || defined(CONFIG_SERIO_I8042_MODULE)
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 78e2ada50cd5a95c7b7527777a870428afa5352c..d380c5e680086ec4627c745f86dc197e7110ea58 100644 (file)
@@ -55,7 +55,7 @@
 #define DMAR_IQT_REG   0x88    /* Invalidation queue tail register */
 #define DMAR_IQ_SHIFT  4       /* Invalidation queue head/tail shift */
 #define DMAR_IQA_REG   0x90    /* Invalidation queue addr register */
-#define DMAR_ICS_REG   0x98    /* Invalidation complete status register */
+#define DMAR_ICS_REG   0x9c    /* Invalidation complete status register */
 #define DMAR_IRTA_REG  0xb8    /* Interrupt remapping table addr register */
 
 #define OFFSET_STRIDE          (9)
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 482ad2d84a32dae333c74cccb2d1394b247d5ae8..672ddc4de4af0511b20a4d269bcae1c517c3d5c4 100644 (file)
@@ -439,6 +439,17 @@ static inline char *hex_byte_pack(char *buf, u8 byte)
        return buf;
 }
 
+extern const char hex_asc_upper[];
+#define hex_asc_upper_lo(x)    hex_asc_upper[((x) & 0x0f)]
+#define hex_asc_upper_hi(x)    hex_asc_upper[((x) & 0xf0) >> 4]
+
+static inline char *hex_byte_pack_upper(char *buf, u8 byte)
+{
+       *buf++ = hex_asc_upper_hi(byte);
+       *buf++ = hex_asc_upper_lo(byte);
+       return buf;
+}
+
 static inline char * __deprecated pack_hex_byte(char *buf, u8 byte)
 {
        return hex_byte_pack(buf, byte);
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 f66b065a8b5ff1af1efdc698aadc248a79175917..df32d2508290aae03f539d0434030bf8a355bbd9 100644 (file)
@@ -39,6 +39,7 @@ enum kobj_ns_type {
  */
 struct kobj_ns_type_operations {
        enum kobj_ns_type type;
+       bool (*current_may_mount)(void);
        void *(*grab_current_ns)(void);
        const void *(*netlink_ns)(struct sock *sk);
        const void *(*initial_ns)(void);
@@ -50,6 +51,7 @@ int kobj_ns_type_registered(enum kobj_ns_type type);
 const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent);
 const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj);
 
+bool kobj_ns_current_may_mount(enum kobj_ns_type type);
 void *kobj_ns_grab_current(enum kobj_ns_type type);
 const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk);
 const void *kobj_ns_initial(enum kobj_ns_type type);
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 ca07b5028b012abd94deabbe5891c6b7f150843f..f279ed9a91631cca7f236d20ef5a29d152332932 100644 (file)
@@ -33,4 +33,7 @@ extern int lockref_get_not_zero(struct lockref *);
 extern int lockref_get_or_lock(struct lockref *);
 extern int lockref_put_or_lock(struct lockref *);
 
+extern void lockref_mark_dead(struct lockref *);
+extern int lockref_get_not_dead(struct lockref *);
+
 #endif /* __LINUX_LOCKREF_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..b3e7a667e03c24ca5c3d1c54c0db5c7b0bdde052 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 {
@@ -125,6 +137,25 @@ extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
 extern void mem_cgroup_replace_page_cache(struct page *oldpage,
                                        struct page *newpage);
 
+static inline void mem_cgroup_oom_enable(void)
+{
+       WARN_ON(current->memcg_oom.may_oom);
+       current->memcg_oom.may_oom = 1;
+}
+
+static inline void mem_cgroup_oom_disable(void)
+{
+       WARN_ON(!current->memcg_oom.may_oom);
+       current->memcg_oom.may_oom = 0;
+}
+
+static inline bool task_in_memcg_oom(struct task_struct *p)
+{
+       return p->memcg_oom.memcg;
+}
+
+bool mem_cgroup_oom_synchronize(bool wait);
+
 #ifdef CONFIG_MEMCG_SWAP
 extern int do_swap_account;
 #endif
@@ -165,17 +196,17 @@ 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);
 }
@@ -348,13 +379,31 @@ static inline void mem_cgroup_end_update_page_stat(struct page *page,
 {
 }
 
+static inline void mem_cgroup_oom_enable(void)
+{
+}
+
+static inline void mem_cgroup_oom_disable(void)
+{
+}
+
+static inline bool task_in_memcg_oom(struct task_struct *p)
+{
+       return false;
+}
+
+static inline bool mem_cgroup_oom_synchronize(bool wait)
+{
+       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)
 {
 }
 
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 09c2300ddb3723188636867fa9b5c21bddab47df..cb358355ef4338c7b39e55df05e0cf539096a77e 100644 (file)
@@ -45,6 +45,7 @@
 #define MAPPER_CTRL_MINOR      236
 #define LOOP_CTRL_MINOR                237
 #define VHOST_NET_MINOR                238
+#define UHID_MINOR             239
 #define MISC_DYNAMIC_MINOR     255
 
 struct device;
index 68029b30c3dc89e2d2620fd41101b2ab05069344..5eb4e31af22b8e05356dfef793c1b96497af8cb3 100644 (file)
@@ -181,7 +181,7 @@ enum {
        MLX5_DEV_CAP_FLAG_TLP_HINTS     = 1LL << 39,
        MLX5_DEV_CAP_FLAG_SIG_HAND_OVER = 1LL << 40,
        MLX5_DEV_CAP_FLAG_DCT           = 1LL << 41,
-       MLX5_DEV_CAP_FLAG_CMDIF_CSUM    = 1LL << 46,
+       MLX5_DEV_CAP_FLAG_CMDIF_CSUM    = 3LL << 46,
 };
 
 enum {
@@ -417,7 +417,7 @@ struct mlx5_init_seg {
        struct health_buffer    health;
        __be32                  rsvd2[884];
        __be32                  health_counter;
-       __be32                  rsvd3[1023];
+       __be32                  rsvd3[1019];
        __be64                  ieee1588_clk;
        __be32                  ieee1588_clk_type;
        __be32                  clr_intx;
index 8888381fc150b8f3f852077407ee8187a54cb7aa..6b8c496572c841d8ec8be70740557f1caf50b79a 100644 (file)
@@ -82,7 +82,7 @@ enum {
 };
 
 enum {
-       MLX5_MAX_EQ_NAME        = 20
+       MLX5_MAX_EQ_NAME        = 32
 };
 
 enum {
@@ -747,8 +747,7 @@ static inline u32 mlx5_idx_to_mkey(u32 mkey_idx)
 
 enum {
        MLX5_PROF_MASK_QP_SIZE          = (u64)1 << 0,
-       MLX5_PROF_MASK_CMDIF_CSUM       = (u64)1 << 1,
-       MLX5_PROF_MASK_MR_CACHE         = (u64)1 << 2,
+       MLX5_PROF_MASK_MR_CACHE         = (u64)1 << 1,
 };
 
 enum {
@@ -758,7 +757,6 @@ enum {
 struct mlx5_profile {
        u64     mask;
        u32     log_max_qp;
-       int     cmdif_csum;
        struct {
                int     size;
                int     limit;
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 329aa307cb7727ad3a593aadb99f30e3f77e027b..45e921401b067b68c9912f82af1c19a1a8c6d048 100644 (file)
@@ -277,7 +277,7 @@ struct pcmcia_device_id {
 #define INPUT_DEVICE_ID_KEY_MIN_INTERESTING    0x71
 #define INPUT_DEVICE_ID_KEY_MAX                0x2ff
 #define INPUT_DEVICE_ID_REL_MAX                0x0f
-#define INPUT_DEVICE_ID_ABS_MAX                0x4f
+#define INPUT_DEVICE_ID_ABS_MAX                0x3f
 #define INPUT_DEVICE_ID_MSC_MAX                0x07
 #define INPUT_DEVICE_ID_LED_MAX                0x0f
 #define INPUT_DEVICE_ID_SND_MAX                0x07
index 73005f9957ead2b95adb4107329434afbbf482a7..38cd98f112a0e4ccb62e32d94a2d1065ce76b2dd 100644 (file)
@@ -48,6 +48,7 @@ struct mnt_namespace;
 #define MNT_INTERNAL   0x4000
 
 #define MNT_LOCK_READONLY      0x400000
+#define MNT_LOCKED             0x800000
 
 struct vfsmount {
        struct dentry *mnt_root;        /* root of the mounted tree */
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 ccd4260834c57da2ea30fc5b20714ef15afe076f..bab49da8a0f0b1bd2e01d516fdd0e39a07162326 100644 (file)
@@ -15,8 +15,8 @@
 #include <linux/spinlock_types.h>
 #include <linux/linkage.h>
 #include <linux/lockdep.h>
-
 #include <linux/atomic.h>
+#include <asm/processor.h>
 
 /*
  * Simple, straightforward mutexes with strict semantics:
@@ -175,8 +175,8 @@ extern void mutex_unlock(struct mutex *lock);
 
 extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
 
-#ifndef CONFIG_HAVE_ARCH_MUTEX_CPU_RELAX
-#define arch_mutex_cpu_relax() cpu_relax()
+#ifndef arch_mutex_cpu_relax
+# define arch_mutex_cpu_relax() cpu_relax()
 #endif
 
 #endif
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 8ed4ae9430533a40b6701be6d9346b033f2f96fd..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);
 };
 
 /*
@@ -2101,6 +2101,15 @@ static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue,
 #endif
 }
 
+/**
+ *     netdev_sent_queue - report the number of bytes queued to hardware
+ *     @dev: network device
+ *     @bytes: number of bytes queued to the hardware device queue
+ *
+ *     Report the number of bytes queued for sending/completion to the network
+ *     device hardware queue. @bytes should be a good approximation and should
+ *     exactly match netdev_completed_queue() @bytes
+ */
 static inline void netdev_sent_queue(struct net_device *dev, unsigned int bytes)
 {
        netdev_tx_sent_queue(netdev_get_tx_queue(dev, 0), bytes);
@@ -2130,6 +2139,16 @@ static inline void netdev_tx_completed_queue(struct netdev_queue *dev_queue,
 #endif
 }
 
+/**
+ *     netdev_completed_queue - report bytes and packets completed by device
+ *     @dev: network device
+ *     @pkts: actual number of packets sent over the medium
+ *     @bytes: actual number of bytes sent over the medium
+ *
+ *     Report the number of bytes and packets transmitted by the network device
+ *     hardware queue over the physical medium, @bytes must exactly match the
+ *     @bytes amount passed to netdev_sent_queue()
+ */
 static inline void netdev_completed_queue(struct net_device *dev,
                                          unsigned int pkts, unsigned int bytes)
 {
@@ -2144,6 +2163,13 @@ static inline void netdev_tx_reset_queue(struct netdev_queue *q)
 #endif
 }
 
+/**
+ *     netdev_reset_queue - reset the packets and bytes count of a network device
+ *     @dev_queue: network device
+ *
+ *     Reset the bytes and packet count of a network device and clear the
+ *     software flow control OFF bit for this network device
+ */
 static inline void netdev_reset_queue(struct net_device *dev_queue)
 {
        netdev_tx_reset_queue(netdev_get_tx_queue(dev_queue, 0));
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..49f52c8f4422ffd8ce6f0e17d33e960e92361076 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 *);
@@ -1436,13 +1455,14 @@ struct nfs_rpc_ops {
        struct inode * (*open_context) (struct inode *dir,
                                struct nfs_open_context *ctx,
                                int open_flags,
-                               struct iattr *iattr);
+                               struct iattr *iattr,
+                               int *);
        int (*have_delegation)(struct inode *, fmode_t);
        int (*return_delegation)(struct inode *);
        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 535cecf1e02f7823a1ec3f416c3b06382ea6d8fa..fcd63baee5f28b3361625cc1877b9a275d221204 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef __OF_IRQ_H
 #define __OF_IRQ_H
 
-#if defined(CONFIG_OF)
-struct of_irq;
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/irq.h>
@@ -10,14 +8,6 @@ struct of_irq;
 #include <linux/ioport.h>
 #include <linux/of.h>
 
-/*
- * irq_of_parse_and_map() is used by all OF enabled platforms; but SPARC
- * implements it differently.  However, the prototype is the same for all,
- * so declare it here regardless of the CONFIG_OF_IRQ setting.
- */
-extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
-
-#if defined(CONFIG_OF_IRQ)
 /**
  * of_irq - container for device_node/irq_specifier pair for an irq controller
  * @controller: pointer to interrupt controller device tree node
@@ -71,11 +61,17 @@ extern int of_irq_to_resource(struct device_node *dev, int index,
 extern int of_irq_count(struct device_node *dev);
 extern int of_irq_to_resource_table(struct device_node *dev,
                struct resource *res, int nr_irqs);
-extern struct device_node *of_irq_find_parent(struct device_node *child);
 
 extern void of_irq_init(const struct of_device_id *matches);
 
-#endif /* CONFIG_OF_IRQ */
+#if defined(CONFIG_OF)
+/*
+ * irq_of_parse_and_map() is used by all OF enabled platforms; but SPARC
+ * implements it differently.  However, the prototype is the same for all,
+ * so declare it here regardless of the CONFIG_OF_IRQ setting.
+ */
+extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
+extern struct device_node *of_irq_find_parent(struct device_node *child);
 
 #else /* !CONFIG_OF */
 static inline unsigned int irq_of_parse_and_map(struct device_node *dev,
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;
 }
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 866e85c5eb94517fc87ca1d49bc9acbde74dcc74..c8ba627c1d608733b8480bb929d9e81d97e57fa0 100644 (file)
@@ -294,9 +294,31 @@ struct ring_buffer;
  */
 struct perf_event {
 #ifdef CONFIG_PERF_EVENTS
-       struct list_head                group_entry;
+       /*
+        * entry onto perf_event_context::event_list;
+        *   modifications require ctx->lock
+        *   RCU safe iterations.
+        */
        struct list_head                event_entry;
+
+       /*
+        * XXX: group_entry and sibling_list should be mutually exclusive;
+        * either you're a sibling on a group, or you're the group leader.
+        * Rework the code to always use the same list element.
+        *
+        * Locked for modification by both ctx->mutex and ctx->lock; holding
+        * either sufficies for read.
+        */
+       struct list_head                group_entry;
        struct list_head                sibling_list;
+
+       /*
+        * We need storage to track the entries in perf_pmu_migrate_context; we
+        * cannot use the event_entry because of RCU and we want to keep the
+        * group in tact which avoids us using the other two entries.
+        */
+       struct list_head                migrate_entry;
+
        struct hlist_node               hlist_entry;
        int                             nr_siblings;
        int                             group_flags;
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 573edfb046c4f5943ea4acb2449a9c6ec3154285..7c5a519d2dcde2bd08816c78f4c59f8d41f8324c 100644 (file)
@@ -5,6 +5,7 @@ struct gpio_em_config {
        unsigned int gpio_base;
        unsigned int irq_base;
        unsigned int number_of_pins;
+       const char *pctl_name;
 };
 
 #endif /* __GPIO_EM_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 */
similarity index 66%
rename from include/linux/platform_data/leds-pca9633.h
rename to include/linux/platform_data/leds-pca963x.h
index c5bf29b6fa7f8c1eddafb23508bb6030509dd7ae..e731f0036329c424dfe31d85d0d9224e65dfc67e 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * PCA9633 LED chip driver.
+ * 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
  * 02110-1301 USA
  */
 
-#ifndef __LINUX_PCA9633_H
-#define __LINUX_PCA9633_H
+#ifndef __LINUX_PCA963X_H
+#define __LINUX_PCA963X_H
 #include <linux/leds.h>
 
-enum pca9633_outdrv {
-       PCA9633_OPEN_DRAIN,
-       PCA9633_TOTEM_POLE, /* aka push-pull */
+enum pca963x_outdrv {
+       PCA963X_OPEN_DRAIN,
+       PCA963X_TOTEM_POLE, /* aka push-pull */
 };
 
-struct pca9633_platform_data {
+enum pca963x_blink_type {
+       PCA963X_SW_BLINK,
+       PCA963X_HW_BLINK,
+};
+
+struct pca963x_platform_data {
        struct led_platform_data leds;
-       enum pca9633_outdrv outdrv;
+       enum pca963x_outdrv outdrv;
+       enum pca963x_blink_type blink_type;
 };
 
-#endif /* __LINUX_PCA9633_H*/
+#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 3b9377d6b7a5fd63b13d02fc238d7da99fbef026..6312dd9ba449b4d65f5bb6bcdc01d606fc2fdfa8 100644 (file)
@@ -17,6 +17,7 @@ extern void add_interrupt_randomness(int irq, int irq_flags);
 extern void get_random_bytes(void *buf, int nbytes);
 extern void get_random_bytes_arch(void *buf, int nbytes);
 void generate_random_uuid(unsigned char uuid_out[16]);
+extern int random_int_secret_init(void);
 
 #ifndef MODULE
 extern const struct file_operations random_fops, urandom_fops;
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 67e13aa5a4781d2c8fdfa8fc902d2bbc90f2a3a0..9bdad43ad228a5501c2dc8b0e6cc77a6da8c7b30 100644 (file)
@@ -40,6 +40,8 @@ enum regulator_status {
 };
 
 /**
+ * struct regulator_linear_range - specify linear voltage ranges
+ *
  * Specify a range of voltages for regulator_map_linar_range() and
  * regulator_list_linear_range().
  *
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..e27baeeda3f470ed99ae899d8de22da062856bf8 100644 (file)
@@ -1393,6 +1393,12 @@ struct task_struct {
                unsigned long memsw_nr_pages; /* uncharged mem+swap usage */
        } memcg_batch;
        unsigned int memcg_kmem_skip_account;
+       struct memcg_oom_info {
+               struct mem_cgroup *memcg;
+               gfp_t gfp_mask;
+               int order;
+               unsigned int may_oom:1;
+       } memcg_oom;
 #endif
 #ifdef CONFIG_UPROBES
        struct uprobe_task *utask;
@@ -2169,15 +2175,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 7ce53ae1266bf04c0305f8b695dc240818a7d4ca..9d37e2b9d3ec030f026117d99de94dfd50b32ab0 100644 (file)
@@ -1492,7 +1492,7 @@ struct security_operations {
        int (*inode_alloc_security) (struct inode *inode);
        void (*inode_free_security) (struct inode *inode);
        int (*inode_init_security) (struct inode *inode, struct inode *dir,
-                                   const struct qstr *qstr, char **name,
+                                   const struct qstr *qstr, const char **name,
                                    void **value, size_t *len);
        int (*inode_create) (struct inode *dir,
                             struct dentry *dentry, umode_t mode);
@@ -1770,7 +1770,7 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
                                 const struct qstr *qstr,
                                 initxattrs initxattrs, void *fs_data);
 int security_old_inode_init_security(struct inode *inode, struct inode *dir,
-                                    const struct qstr *qstr, char **name,
+                                    const struct qstr *qstr, const char **name,
                                     void **value, size_t *len);
 int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode);
 int security_inode_link(struct dentry *old_dentry, struct inode *dir,
@@ -2094,8 +2094,8 @@ static inline int security_inode_init_security(struct inode *inode,
 static inline int security_old_inode_init_security(struct inode *inode,
                                                   struct inode *dir,
                                                   const struct qstr *qstr,
-                                                  char **name, void **value,
-                                                  size_t *len)
+                                                  const char **name,
+                                                  void **value, size_t *len)
 {
        return -EOPNOTSUPP;
 }
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 2ddb48d9312c260e1e41a87ac25a19314f2aa379..c2d89335f6370d6e72a06470290a2a6e8a4cac7b 100644 (file)
@@ -498,7 +498,7 @@ struct sk_buff {
         * headers if needed
         */
        __u8                    encapsulation:1;
-       /* 7/9 bit hole (depending on ndisc_nodetype presence) */
+       /* 6/8 bit hole (depending on ndisc_nodetype presence) */
        kmemcheck_bitfield_end(flags2);
 
 #if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
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..731f5237d5f4e0f87dd817e15983f509d3b4d483 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)
@@ -192,6 +155,12 @@ smp_call_function_any(const struct cpumask *mask, smp_call_func_t func,
 
 static inline void kick_all_cpus_sync(void) {  }
 
+static inline void __smp_call_function_single(int cpuid,
+               struct call_single_data *data, int wait)
+{
+       on_each_cpu(data->func, data->info, wait);
+}
+
 #endif /* !SMP */
 
 /*
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..9d3f1a5b6178a9dd1aa3914b35051b96f5ceb279 100644 (file)
 
 #include <asm/timex.h>
 
+#ifndef random_get_entropy
+/*
+ * The random_get_entropy() function is used by the /dev/random driver
+ * in order to extract entropy via the relative unpredictability of
+ * when an interrupt takes places versus a high speed, fine-grained
+ * timing source or cycle counter.  Since it will be occurred on every
+ * single interrupt, it must have a very low cost/overhead.
+ *
+ * By default we use get_cycles() for this purpose, but individual
+ * architectures may override this in their asm/timex.h header file.
+ */
+#define random_get_entropy()   get_cycles()
+#endif
+
 /*
  * SHIFT_PLL is used as a dampening factor to define how much we
  * adjust the frequency correction for a given offset in PLL mode.
@@ -141,6 +155,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 f9a7e7bc925be61322a24304076503bd918a520a..11d85b9c1b081af6a9f4f30ac3c1458766ed4238 100644 (file)
@@ -12,7 +12,7 @@ struct usb_phy_gen_xceiv_platform_data {
        unsigned int needs_reset:1;
 };
 
-#if IS_ENABLED(CONFIG_NOP_USB_XCEIV)
+#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
 /* sometimes transceivers are accessed only through e.g. ULPI */
 extern void usb_nop_xceiv_register(void);
 extern void usb_nop_xceiv_unregister(void);
index 9cb2fe8ca944d5095043dd7b7ce71116a3fc21eb..e303eef94dd5cea92d16d7ae63aa35f5c3f1d4bb 100644 (file)
@@ -42,6 +42,7 @@ struct usbnet {
        struct usb_host_endpoint *status;
        unsigned                maxpacket;
        struct timer_list       delay;
+       const char              *padding_pkt;
 
        /* protocol/interface state */
        struct net_device       *net;
index bf99cd01be206ebeb170d826e176c3ac22e1493e..630356866030d88a355390a932105ff9c86b98bb 100644 (file)
@@ -66,7 +66,9 @@
        US_FLAG(INITIAL_READ10, 0x00100000)                     \
                /* Initial READ(10) (and others) must be retried */     \
        US_FLAG(WRITE_CACHE,    0x00200000)                     \
-               /* Write Cache status is not available */
+               /* Write Cache status is not available */       \
+       US_FLAG(NEEDS_CAP16,    0x00400000)
+               /* cannot handle READ_CAPACITY_10 */
 
 #define US_FLAG(name, value)   US_FL_##name = value ,
 enum { US_DO_ALL_FLAGS };
index 14105c26a83618da5d91ae09331fb83ba8f8ad6b..4db29859464f3af3d78caafa41a1e7525034a589 100644 (file)
@@ -27,8 +27,6 @@ struct user_namespace {
        kuid_t                  owner;
        kgid_t                  group;
        unsigned int            proc_inum;
-       bool                    may_mount_sysfs;
-       bool                    may_mount_proc;
 };
 
 extern struct user_namespace init_user_ns;
@@ -85,6 +83,4 @@ static inline void put_user_ns(struct user_namespace *ns)
 
 #endif
 
-void update_mnt_policy(struct user_namespace *userns);
-
 #endif /* _LINUX_USER_H */
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 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 fdbafc6841cfd609cfd0c810ddcf4c3df7a33ed2..91b0a68d38dc2a4941c1b36a8cac270af0136422 100644 (file)
@@ -31,7 +31,7 @@ struct xattr_handler {
 };
 
 struct xattr {
-       char *name;
+       const char *name;
        void *value;
        size_t value_len;
 };
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 fb314de2b61ba228059b1f09cb916d7d275a6a9b..86505bfa5d2c4829698d21ce81ba47575b504941 100644 (file)
@@ -67,6 +67,10 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
 int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr);
 #endif
 
+bool ipv6_chk_custom_prefix(const struct in6_addr *addr,
+                                  const unsigned int prefix_len,
+                                  struct net_device *dev);
+
 int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev);
 
 struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net,
index aaeaf0938ec0af1181c4660c8fa0468937e1bc74..15f10841e2b5ddedb94dadfe166e2fe19b09cfee 100644 (file)
@@ -104,6 +104,7 @@ enum {
 enum {
        HCI_SETUP,
        HCI_AUTO_OFF,
+       HCI_RFKILLED,
        HCI_MGMT,
        HCI_PAIRABLE,
        HCI_SERVICE_CACHE,
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 f0d70f066f3ddc59a0c1c7bb5e58daf1c4b3c3a4..9c4d37ec45a1e5dd0536dcbef7fdfa8eac684401 100644 (file)
@@ -723,8 +723,6 @@ struct ip_vs_dest_dst {
        struct rcu_head         rcu_head;
 };
 
-/* In grace period after removing */
-#define IP_VS_DEST_STATE_REMOVING      0x01
 /*
  *     The real server destination forwarding entry
  *     with ip address, port number, and so on.
@@ -742,7 +740,7 @@ struct ip_vs_dest {
 
        atomic_t                refcnt;         /* reference counter */
        struct ip_vs_stats      stats;          /* statistics */
-       unsigned long           state;          /* state flags */
+       unsigned long           idle_start;     /* start time, jiffies */
 
        /* connection counters and thresholds */
        atomic_t                activeconns;    /* active connections */
@@ -756,14 +754,13 @@ struct ip_vs_dest {
        struct ip_vs_dest_dst __rcu *dest_dst;  /* cached dst info */
 
        /* for virtual service */
-       struct ip_vs_service    *svc;           /* service it belongs to */
+       struct ip_vs_service __rcu *svc;        /* service it belongs to */
        __u16                   protocol;       /* which protocol (TCP/UDP) */
        __be16                  vport;          /* virtual port number */
        union nf_inet_addr      vaddr;          /* virtual IP address */
        __u32                   vfwmark;        /* firewall mark of service */
 
        struct list_head        t_list;         /* in dest_trash */
-       struct rcu_head         rcu_head;
        unsigned int            in_rs_table:1;  /* we are in rs_table */
 };
 
@@ -1649,7 +1646,7 @@ static inline void ip_vs_conn_drop_conntrack(struct ip_vs_conn *cp)
 /* CONFIG_IP_VS_NFCT */
 #endif
 
-static inline unsigned int
+static inline int
 ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
 {
        /*
index 4fbf02aa2ec1e76a5c18257b0b73949e501c56a5..0f7558b638ae6ff9d0cde2b9e45e13990269005b 100644 (file)
@@ -112,6 +112,7 @@ struct mrp_applicant {
        struct mrp_application  *app;
        struct net_device       *dev;
        struct timer_list       join_timer;
+       struct timer_list       periodic_timer;
 
        spinlock_t              lock;
        struct sk_buff_head     queue;
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 1313456a0994e03cab0859e7960773b0115f8652..9d22f08896c6c16d5a1c26fad0ef65461980d02a 100644 (file)
@@ -74,6 +74,7 @@ struct net {
        struct hlist_head       *dev_index_head;
        unsigned int            dev_base_seq;   /* protected by rtnl_mutex */
        int                     ifindex;
+       unsigned int            dev_unreg_count;
 
        /* core fib_rules */
        struct list_head        rules_ops;
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 806f54a290d60476e0e25193d3565b611febece3..f572f313d6f1e0d7ae61f345b9aeb15a7dfea0a2 100644 (file)
@@ -56,7 +56,7 @@ struct synproxy_options {
 
 struct tcphdr;
 struct xt_synproxy_info;
-extern void synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
+extern bool synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
                                   const struct tcphdr *th,
                                   struct synproxy_options *opts);
 extern unsigned int synproxy_options_size(const struct synproxy_options *opts);
index 6ca975bebd37deea98470a75053f399671092498..c2e542b27a5a8316f3b105b2338bc96d5698690e 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <linux/types.h>
 
-extern void net_secret_init(void);
 extern __u32 secure_ip_id(__be32 daddr);
 extern __u32 secure_ipv6_id(const __be32 daddr[4]);
 extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
index 6ba2e7b0e2b1300f3983ef4d3c845e257d46c579..1d37a8086bed53575fedc30b9c1db750d4cd2822 100644 (file)
@@ -409,6 +409,11 @@ struct sock {
        void                    (*sk_destruct)(struct sock *sk);
 };
 
+#define __sk_user_data(sk) ((*((void __rcu **)&(sk)->sk_user_data)))
+
+#define rcu_dereference_sk_user_data(sk)       rcu_dereference(__sk_user_data((sk)))
+#define rcu_assign_sk_user_data(sk, ptr)       rcu_assign_pointer(__sk_user_data((sk)), ptr)
+
 /*
  * SK_CAN_REUSE and SK_NO_REUSE on a socket mean that the socket is OK
  * or not whether his port will be reused by someone else. SK_FORCE_REUSE
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 60ae7c3db912de7e068452de1a1c1978cad0a662..4c2301d2ef1aa979ea0d6594ad1b6404368b920b 100644 (file)
@@ -618,6 +618,7 @@ TRACE_EVENT(block_rq_remap,
                __field( unsigned int,  nr_sector       )
                __field( dev_t,         old_dev         )
                __field( sector_t,      old_sector      )
+               __field( unsigned int,  nr_bios         )
                __array( char,          rwbs,   RWBS_LEN)
        ),
 
@@ -627,15 +628,16 @@ TRACE_EVENT(block_rq_remap,
                __entry->nr_sector      = blk_rq_sectors(rq);
                __entry->old_dev        = dev;
                __entry->old_sector     = from;
+               __entry->nr_bios        = blk_rq_count_bios(rq);
                blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq));
        ),
 
-       TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu",
+       TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu %u",
                  MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
                  (unsigned long long)__entry->sector,
                  __entry->nr_sector,
                  MAJOR(__entry->old_dev), MINOR(__entry->old_dev),
-                 (unsigned long long)__entry->old_sector)
+                 (unsigned long long)__entry->old_sector, __entry->nr_bios)
 );
 
 #endif /* _TRACE_BLOCK_H */
index 2902657ba766bb7dc1a9949b1f0436816615484a..f18b3b76e01e22e00c00ee133b2ebdc1013bcc62 100644 (file)
@@ -42,6 +42,7 @@ struct extent_buffer;
                { BTRFS_TREE_LOG_OBJECTID,      "TREE_LOG"      },      \
                { BTRFS_QUOTA_TREE_OBJECTID,    "QUOTA_TREE"    },      \
                { BTRFS_TREE_RELOC_OBJECTID,    "TREE_RELOC"    },      \
+               { BTRFS_UUID_TREE_OBJECTID,     "UUID_RELOC"    },      \
                { BTRFS_DATA_RELOC_TREE_OBJECTID, "DATA_RELOC_TREE" })
 
 #define show_root_type(obj)                                            \
@@ -439,7 +440,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 +482,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 +546,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 +593,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 550811712f78c71aad43b4a531b07e1df536b64f..28acbaf4a81ec091a54740c54adfd57ec2f9ad59 100644 (file)
@@ -223,6 +223,8 @@ struct drm_mode_get_connector {
        __u32 connection;
        __u32 mm_width, mm_height; /**< HxW in millimeters */
        __u32 subpixel;
+
+       __u32 pad;
 };
 
 #define DRM_MODE_PROP_PENDING  (1<<0)
index fa8b3adf9ffbbc478a7aae0f83ffbe3bd584a91b..46d41e8b0dccec30ec5b52f6dc772bf9e3088dc6 100644 (file)
@@ -1007,4 +1007,6 @@ struct drm_radeon_info {
 #define SI_TILE_MODE_DEPTH_STENCIL_2D_4AA      3
 #define SI_TILE_MODE_DEPTH_STENCIL_2D_8AA      2
 
+#define CIK_TILE_MODE_DEPTH_STENCIL_1D         5
+
 #endif
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 76457eef172ae05ce63ca22c17700f2271b8e39e..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 */
 
@@ -194,6 +195,8 @@ struct input_keymap_entry {
 #define SYN_CONFIG             1
 #define SYN_MT_REPORT          2
 #define SYN_DROPPED            3
+#define SYN_MAX                        0xf
+#define SYN_CNT                        (SYN_MAX+1)
 
 /*
  * Keys and buttons
@@ -716,14 +719,6 @@ struct input_keymap_entry {
 #define BTN_DPAD_LEFT          0x222
 #define BTN_DPAD_RIGHT         0x223
 
-#define BTN_FRET_FAR_UP                0x224
-#define BTN_FRET_UP            0x225
-#define BTN_FRET_MID           0x226
-#define BTN_FRET_LOW           0x227
-#define BTN_FRET_FAR_LOW       0x228
-#define BTN_STRUM_BAR_UP       0x229
-#define BTN_STRUM_BAR_DOWN     0x22a
-
 #define BTN_TRIGGER_HAPPY              0x2c0
 #define BTN_TRIGGER_HAPPY1             0x2c0
 #define BTN_TRIGGER_HAPPY2             0x2c1
@@ -837,21 +832,8 @@ struct input_keymap_entry {
 #define ABS_MT_TOOL_X          0x3c    /* Center X tool position */
 #define ABS_MT_TOOL_Y          0x3d    /* Center Y tool position */
 
-/* Drums and guitars (mostly toys) */
-#define ABS_TOM_FAR_LEFT       0x40
-#define ABS_TOM_LEFT           0x41
-#define ABS_TOM_RIGHT          0x42
-#define ABS_TOM_FAR_RIGHT      0x43
-#define ABS_CYMBAL_FAR_LEFT    0x44
-#define ABS_CYMBAL_LEFT                0x45
-#define ABS_CYMBAL_RIGHT       0x46
-#define ABS_CYMBAL_FAR_RIGHT   0x47
-#define ABS_BASS               0x48
-#define ABS_HI_HAT             0x49
-#define ABS_FRET_BOARD         0x4a    /* Guitar fret board, vertical pos */
-#define ABS_WHAMMY_BAR         0x4b    /* Guitar whammy bar (or vibrato) */
-
-#define ABS_MAX                        0x4f
+
+#define ABS_MAX                        0x3f
 #define ABS_CNT                        (ABS_MAX+1)
 
 /*
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..009a655a5d354c51e20fb34cb12ca653e94f9b71 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,
@@ -380,10 +380,13 @@ struct perf_event_mmap_page {
        union {
                __u64   capabilities;
                struct {
-                       __u64   cap_usr_time            : 1,
-                               cap_usr_rdpmc           : 1,
-                               cap_usr_time_zero       : 1,
-                               cap_____res             : 61;
+                       __u64   cap_bit0                : 1, /* Always 0, deprecated, see commit 860f085b74e9 */
+                               cap_bit0_is_deprecated  : 1, /* Always 1, signals that bit 0 is zero */
+
+                               cap_user_rdpmc          : 1, /* The RDPMC instruction can be used to read counts */
+                               cap_user_time           : 1, /* The time_* fields are used */
+                               cap_user_time_zero      : 1, /* The time_zero field is used */
+                               cap_____res             : 59;
                };
        };
 
@@ -442,12 +445,13 @@ struct perf_event_mmap_page {
         *               ((rem * time_mult) >> time_shift);
         */
        __u64   time_zero;
+       __u32   size;                   /* Header size up to __reserved[] fields. */
 
                /*
                 * Hole for extension of the self monitor capabilities
                 */
 
-       __u64   __reserved[119];        /* align to 1k */
+       __u8    __reserved[118*8+4];    /* align to 1k. */
 
        /*
         * Control data for the mmap() data buffer.
@@ -528,6 +532,7 @@ enum perf_event_type {
         *      u64                             len;
         *      u64                             pgoff;
         *      char                            filename[];
+        *      struct sample_id                sample_id;
         * };
         */
        PERF_RECORD_MMAP                        = 1,
index d8ce17c2459a1f8ce79d67267e19d9a581776439..38fdd648be214c1e94851686ae308a5a42543cbf 100644 (file)
@@ -16,7 +16,7 @@ struct reiserfs_xattr_header {
 };
 
 struct reiserfs_security_handle {
-       char *name;
+       const char *name;
        void *value;
        size_t length;
 };
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 af310afbef2867e987973cc341a7b418f7413068..63d3e8f2970c1377ec822bcb9db8ee306faecee6 100644 (file)
@@ -76,6 +76,7 @@
 #include <linux/elevator.h>
 #include <linux/sched_clock.h>
 #include <linux/context_tracking.h>
+#include <linux/random.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -780,6 +781,7 @@ static void __init do_basic_setup(void)
        do_ctors();
        usermodehelper_enable();
        do_initcalls();
+       random_int_secret_init();
 }
 
 static void __init do_pre_smp_initcalls(void)
index b65fdf1a09dd1f81b32731bfa2fcb455389ea63c..558aa91186b6ced1a27b1e05b65c5ee129e0a175 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
@@ -167,12 +165,21 @@ static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
        ipc_rmid(&msg_ids(ns), &s->q_perm);
 }
 
+static void msg_rcu_free(struct rcu_head *head)
+{
+       struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
+       struct msg_queue *msq = ipc_rcu_to_struct(p);
+
+       security_msg_queue_free(msq);
+       ipc_rcu_free(head);
+}
+
 /**
  * newque - Create a new msg queue
  * @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)
 {
@@ -191,15 +198,14 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
        msq->q_perm.security = NULL;
        retval = security_msg_queue_alloc(msq);
        if (retval) {
-               ipc_rcu_putref(msq);
+               ipc_rcu_putref(msq, ipc_rcu_free);
                return retval;
        }
 
        /* ipc_addid() locks msq upon success. */
        id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
        if (id < 0) {
-               security_msg_queue_free(msq);
-               ipc_rcu_putref(msq);
+               ipc_rcu_putref(msq, msg_rcu_free);
                return id;
        }
 
@@ -259,8 +265,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,19 +276,19 @@ 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);
                free_msg(msg);
        }
        atomic_sub(msq->q_cbytes, &ns->msg_bytes);
-       security_msg_queue_free(msq);
-       ipc_rcu_putref(msq);
+       ipc_rcu_putref(msq, msg_rcu_free);
 }
 
 /*
- * 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 +392,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 +409,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 +465,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 +500,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 +511,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;
@@ -689,6 +695,12 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
                if (ipcperms(ns, &msq->q_perm, S_IWUGO))
                        goto out_unlock0;
 
+               /* raced with RMID? */
+               if (msq->q_perm.deleted) {
+                       err = -EIDRM;
+                       goto out_unlock0;
+               }
+
                err = security_msg_queue_msgsnd(msq, msg, msgflg);
                if (err)
                        goto out_unlock0;
@@ -718,7 +730,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
                rcu_read_lock();
                ipc_lock_object(&msq->q_perm);
 
-               ipc_rcu_putref(msq);
+               ipc_rcu_putref(msq, ipc_rcu_free);
                if (msq->q_perm.deleted) {
                        err = -EIDRM;
                        goto out_unlock0;
@@ -895,6 +907,13 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
                        goto out_unlock1;
 
                ipc_lock_object(&msq->q_perm);
+
+               /* raced with RMID? */
+               if (msq->q_perm.deleted) {
+                       msg = ERR_PTR(-EIDRM);
+                       goto out_unlock0;
+               }
+
                msg = find_msg(msq, &msgtyp, mode);
                if (!IS_ERR(msg)) {
                        /*
index 7ee61bf449332bbb556f4742e72c8f54c8111d89..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)
@@ -171,7 +172,7 @@ static int ipcns_install(struct nsproxy *nsproxy, void *new)
 {
        struct ipc_namespace *ns = new;
        if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
-           !nsown_capable(CAP_SYS_ADMIN))
+           !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
                return -EPERM;
 
        /* Ditch state from the old ipc namespace */
index 41088899783d4106140333014a722da531494838..db9d241af133d770cb0a95a22cacf257f79b1215 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -243,71 +243,122 @@ static void merge_queues(struct sem_array *sma)
        }
 }
 
+static void sem_rcu_free(struct rcu_head *head)
+{
+       struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
+       struct sem_array *sma = ipc_rcu_to_struct(p);
+
+       security_sem_free(sma);
+       ipc_rcu_free(head);
+}
+
+/*
+ * Wait until all currently ongoing simple ops have completed.
+ * Caller must own sem_perm.lock.
+ * New simple ops cannot start, because simple ops first check
+ * that sem_perm.lock is free.
+ * that a) sem_perm.lock is free and b) complex_count is 0.
+ */
+static void sem_wait_array(struct sem_array *sma)
+{
+       int i;
+       struct sem *sem;
+
+       if (sma->complex_count)  {
+               /* The thread that increased sma->complex_count waited on
+                * all sem->lock locks. Thus we don't need to wait again.
+                */
+               return;
+       }
+
+       for (i = 0; i < sma->sem_nsems; i++) {
+               sem = sma->sem_base + i;
+               spin_unlock_wait(&sem->lock);
+       }
+}
+
 /*
  * If the request contains only one semaphore operation, and there are
  * no complex transactions pending, lock only the semaphore involved.
  * Otherwise, lock the entire semaphore array, since we either have
  * multiple semaphores in our own semops, or we need to look at
  * semaphores from other pending complex operations.
- *
- * Carefully guard against sma->complex_count changing between zero
- * and non-zero while we are spinning for the lock. The value of
- * sma->complex_count cannot change while we are holding the lock,
- * so sem_unlock should be fine.
- *
- * The global lock path checks that all the local locks have been released,
- * checking each local lock once. This means that the local lock paths
- * cannot start their critical sections while the global lock is held.
  */
 static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
                              int nsops)
 {
-       int locknum;
- again:
-       if (nsops == 1 && !sma->complex_count) {
-               struct sem *sem = sma->sem_base + sops->sem_num;
+       struct sem *sem;
 
-               /* Lock just the semaphore we are interested in. */
-               spin_lock(&sem->lock);
+       if (nsops != 1) {
+               /* Complex operation - acquire a full lock */
+               ipc_lock_object(&sma->sem_perm);
 
-               /*
-                * If sma->complex_count was set while we were spinning,
-                * we may need to look at things we did not lock here.
+               /* And wait until all simple ops that are processed
+                * right now have dropped their locks.
                 */
-               if (unlikely(sma->complex_count)) {
-                       spin_unlock(&sem->lock);
-                       goto lock_array;
-               }
+               sem_wait_array(sma);
+               return -1;
+       }
+
+       /*
+        * Only one semaphore affected - try to optimize locking.
+        * The rules are:
+        * - optimized locking is possible if no complex operation
+        *   is either enqueued or processed right now.
+        * - The test for enqueued complex ops is simple:
+        *      sma->complex_count != 0
+        * - Testing for complex ops that are processed right now is
+        *   a bit more difficult. Complex ops acquire the full lock
+        *   and first wait that the running simple ops have completed.
+        *   (see above)
+        *   Thus: If we own a simple lock and the global lock is free
+        *      and complex_count is now 0, then it will stay 0 and
+        *      thus just locking sem->lock is sufficient.
+        */
+       sem = sma->sem_base + sops->sem_num;
 
+       if (sma->complex_count == 0) {
                /*
-                * Another process is holding the global lock on the
-                * sem_array; we cannot enter our critical section,
-                * but have to wait for the global lock to be released.
+                * It appears that no complex operation is around.
+                * Acquire the per-semaphore lock.
                 */
-               if (unlikely(spin_is_locked(&sma->sem_perm.lock))) {
-                       spin_unlock(&sem->lock);
-                       spin_unlock_wait(&sma->sem_perm.lock);
-                       goto again;
+               spin_lock(&sem->lock);
+
+               /* Then check that the global lock is free */
+               if (!spin_is_locked(&sma->sem_perm.lock)) {
+                       /* spin_is_locked() is not a memory barrier */
+                       smp_mb();
+
+                       /* Now repeat the test of complex_count:
+                        * It can't change anymore until we drop sem->lock.
+                        * Thus: if is now 0, then it will stay 0.
+                        */
+                       if (sma->complex_count == 0) {
+                               /* fast path successful! */
+                               return sops->sem_num;
+                       }
                }
+               spin_unlock(&sem->lock);
+       }
 
-               locknum = sops->sem_num;
+       /* slow path: acquire the full lock */
+       ipc_lock_object(&sma->sem_perm);
+
+       if (sma->complex_count == 0) {
+               /* False alarm:
+                * There is no complex operation, thus we can switch
+                * back to the fast path.
+                */
+               spin_lock(&sem->lock);
+               ipc_unlock_object(&sma->sem_perm);
+               return sops->sem_num;
        } else {
-               int i;
-               /*
-                * Lock the semaphore array, and wait for all of the
-                * individual semaphore locks to go away.  The code
-                * above ensures no new single-lock holders will enter
-                * their critical section while the array lock is held.
+               /* Not a false alarm, thus complete the sequence for a
+                * full lock.
                 */
- lock_array:
-               ipc_lock_object(&sma->sem_perm);
-               for (i = 0; i < sma->sem_nsems; i++) {
-                       struct sem *sem = sma->sem_base + i;
-                       spin_unlock_wait(&sem->lock);
-               }
-               locknum = -1;
+               sem_wait_array(sma);
+               return -1;
        }
-       return locknum;
 }
 
 static inline void sem_unlock(struct sem_array *sma, int locknum)
@@ -322,7 +373,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.
@@ -374,12 +425,7 @@ static inline struct sem_array *sem_obtain_object_check(struct ipc_namespace *ns
 static inline void sem_lock_and_putref(struct sem_array *sma)
 {
        sem_lock(sma, NULL, -1);
-       ipc_rcu_putref(sma);
-}
-
-static inline void sem_putref(struct sem_array *sma)
-{
-       ipc_rcu_putref(sma);
+       ipc_rcu_putref(sma, ipc_rcu_free);
 }
 
 static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
@@ -426,7 +472,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)
@@ -458,14 +504,13 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
        sma->sem_perm.security = NULL;
        retval = security_sem_alloc(sma);
        if (retval) {
-               ipc_rcu_putref(sma);
+               ipc_rcu_putref(sma, ipc_rcu_free);
                return retval;
        }
 
        id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
        if (id < 0) {
-               security_sem_free(sma);
-               ipc_rcu_putref(sma);
+               ipc_rcu_putref(sma, sem_rcu_free);
                return id;
        }
        ns->used_sems += nsems;
@@ -492,7 +537,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 +548,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)
@@ -872,6 +917,24 @@ again:
        return semop_completed;
 }
 
+/**
+ * set_semotime(sma, sops) - set sem_otime
+ * @sma: semaphore array
+ * @sops: operations that modified the array, may be NULL
+ *
+ * sem_otime is replicated to avoid cache line trashing.
+ * This function sets one instance to the current time.
+ */
+static void set_semotime(struct sem_array *sma, struct sembuf *sops)
+{
+       if (sops == NULL) {
+               sma->sem_base[0].sem_otime = get_seconds();
+       } else {
+               sma->sem_base[sops[0].sem_num].sem_otime =
+                                                       get_seconds();
+       }
+}
+
 /**
  * do_smart_update(sma, sops, nsops, otime, pt) - optimized update_queue
  * @sma: semaphore array
@@ -922,17 +985,10 @@ static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsop
                        }
                }
        }
-       if (otime) {
-               if (sops == NULL) {
-                       sma->sem_base[0].sem_otime = get_seconds();
-               } else {
-                       sma->sem_base[sops[0].sem_num].sem_otime =
-                                                               get_seconds();
-               }
-       }
+       if (otime)
+               set_semotime(sma, sops);
 }
 
-
 /* The following counts are associated to each semaphore:
  *   semncnt        number of tasks waiting on semval being nonzero
  *   semzcnt        number of tasks waiting on semval being zero
@@ -994,8 +1050,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)
@@ -1047,8 +1103,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
 
        wake_up_sem_queue_do(&tasks);
        ns->used_sems -= sma->sem_nsems;
-       security_sem_free(sma);
-       ipc_rcu_putref(sma);
+       ipc_rcu_putref(sma, sem_rcu_free);
 }
 
 static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, int version)
@@ -1116,7 +1171,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 +1180,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;
@@ -1227,6 +1282,12 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
 
        sem_lock(sma, NULL, -1);
 
+       if (sma->sem_perm.deleted) {
+               sem_unlock(sma, -1);
+               rcu_read_unlock();
+               return -EIDRM;
+       }
+
        curr = &sma->sem_base[semnum];
 
        ipc_assert_locked_object(&sma->sem_perm);
@@ -1281,28 +1342,28 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                int i;
 
                sem_lock(sma, NULL, -1);
+               if (sma->sem_perm.deleted) {
+                       err = -EIDRM;
+                       goto out_unlock;
+               }
                if(nsems > SEMMSL_FAST) {
                        if (!ipc_rcu_getref(sma)) {
-                               sem_unlock(sma, -1);
-                               rcu_read_unlock();
                                err = -EIDRM;
-                               goto out_free;
+                               goto out_unlock;
                        }
                        sem_unlock(sma, -1);
                        rcu_read_unlock();
                        sem_io = ipc_alloc(sizeof(ushort)*nsems);
                        if(sem_io == NULL) {
-                               sem_putref(sma);
+                               ipc_rcu_putref(sma, ipc_rcu_free);
                                return -ENOMEM;
                        }
 
                        rcu_read_lock();
                        sem_lock_and_putref(sma);
                        if (sma->sem_perm.deleted) {
-                               sem_unlock(sma, -1);
-                               rcu_read_unlock();
                                err = -EIDRM;
-                               goto out_free;
+                               goto out_unlock;
                        }
                }
                for (i = 0; i < sma->sem_nsems; i++)
@@ -1320,28 +1381,28 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                struct sem_undo *un;
 
                if (!ipc_rcu_getref(sma)) {
-                       rcu_read_unlock();
-                       return -EIDRM;
+                       err = -EIDRM;
+                       goto out_rcu_wakeup;
                }
                rcu_read_unlock();
 
                if(nsems > SEMMSL_FAST) {
                        sem_io = ipc_alloc(sizeof(ushort)*nsems);
                        if(sem_io == NULL) {
-                               sem_putref(sma);
+                               ipc_rcu_putref(sma, ipc_rcu_free);
                                return -ENOMEM;
                        }
                }
 
                if (copy_from_user (sem_io, p, nsems*sizeof(ushort))) {
-                       sem_putref(sma);
+                       ipc_rcu_putref(sma, ipc_rcu_free);
                        err = -EFAULT;
                        goto out_free;
                }
 
                for (i = 0; i < nsems; i++) {
                        if (sem_io[i] > SEMVMX) {
-                               sem_putref(sma);
+                               ipc_rcu_putref(sma, ipc_rcu_free);
                                err = -ERANGE;
                                goto out_free;
                        }
@@ -1349,10 +1410,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                rcu_read_lock();
                sem_lock_and_putref(sma);
                if (sma->sem_perm.deleted) {
-                       sem_unlock(sma, -1);
-                       rcu_read_unlock();
                        err = -EIDRM;
-                       goto out_free;
+                       goto out_unlock;
                }
 
                for (i = 0; i < nsems; i++)
@@ -1376,6 +1435,10 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                goto out_rcu_wakeup;
 
        sem_lock(sma, NULL, -1);
+       if (sma->sem_perm.deleted) {
+               err = -EIDRM;
+               goto out_unlock;
+       }
        curr = &sma->sem_base[semnum];
 
        switch (cmd) {
@@ -1431,9 +1494,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 +1511,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 +1550,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;
 }
 
@@ -1629,7 +1692,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        /* step 2: allocate new undo structure */
        new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
        if (!new) {
-               sem_putref(sma);
+               ipc_rcu_putref(sma, ipc_rcu_free);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -1781,6 +1844,10 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
        if (error)
                goto out_rcu_wakeup;
 
+       error = -EIDRM;
+       locknum = sem_lock(sma, sops, nsops);
+       if (sma->sem_perm.deleted)
+               goto out_unlock_free;
        /*
         * semid identifiers are not unique - find_alloc_undo may have
         * allocated an undo structure, it was invalidated by an RMID
@@ -1788,19 +1855,22 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
         * This case can be detected checking un->semid. The existence of
         * "un" itself is guaranteed by rcu.
         */
-       error = -EIDRM;
-       locknum = sem_lock(sma, sops, nsops);
        if (un && un->semid == -1)
                goto out_unlock_free;
 
        error = perform_atomic_semop(sma, sops, nsops, un,
                                        task_tgid_vnr(current));
-       if (error <= 0) {
-               if (alter && error == 0)
+       if (error == 0) {
+               /* If the operation was successful, then do
+                * the required updates.
+                */
+               if (alter)
                        do_smart_update(sma, sops, nsops, 1, &tasks);
-
-               goto out_unlock_free;
+               else
+                       set_semotime(sma, sops);
        }
+       if (error <= 0)
+               goto out_unlock_free;
 
        /* We need to sleep on this operation, so we put the current
         * task into the pending queue and go to sleep.
@@ -1997,6 +2067,12 @@ void exit_sem(struct task_struct *tsk)
                }
 
                sem_lock(sma, NULL, -1);
+               /* exit_sem raced with IPC_RMID, nothing to do */
+               if (sma->sem_perm.deleted) {
+                       sem_unlock(sma, -1);
+                       rcu_read_unlock();
+                       continue;
+               }
                un = __lookup_undo(ulp, semid);
                if (un == NULL) {
                        /* exit_sem raced with IPC_RMID+semget() that created
@@ -2059,6 +2135,14 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
        struct sem_array *sma = it;
        time_t sem_otime;
 
+       /*
+        * The proc interface isn't aware of sem_lock(), it calls
+        * ipc_lock_object() directly (in sysvipc_find_ipc).
+        * In order to stay compatible with sem_lock(), we must wait until
+        * all simple semop() calls have left their critical regions.
+        */
+       sem_wait_array(sma);
+
        sem_otime = get_semotime(sma);
 
        return seq_printf(s,
index c6b4ad5ce3b7b53df40b5934bb823fff4de9f9c8..d69739610fd4384323004c46782116d54db6bbd5 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,15 +167,13 @@ 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)
+static void shm_rcu_free(struct rcu_head *head)
 {
-       struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
-
-       if (IS_ERR(ipcp))
-               return (struct shmid_kernel *)ipcp;
+       struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
+       struct shmid_kernel *shp = ipc_rcu_to_struct(p);
 
-       return container_of(ipcp, struct shmid_kernel, shm_perm);
+       security_shm_free(shp);
+       ipc_rcu_free(head);
 }
 
 static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
@@ -182,7 +203,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)
@@ -196,8 +217,7 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
                user_shm_unlock(file_inode(shp->shm_file)->i_size,
                                                shp->mlock_user);
        fput (shp->shm_file);
-       security_shm_free(shp);
-       ipc_rcu_putref(shp);
+       ipc_rcu_putref(shp, shm_rcu_free);
 }
 
 /*
@@ -230,7 +250,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 +261,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 +295,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 +306,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 +320,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 +335,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 +472,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)
@@ -485,7 +505,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
        shp->shm_perm.security = NULL;
        error = security_shm_alloc(shp);
        if (error) {
-               ipc_rcu_putref(shp);
+               ipc_rcu_putref(shp, ipc_rcu_free);
                return error;
        }
 
@@ -554,13 +574,12 @@ no_id:
                user_shm_unlock(size, shp->mlock_user);
        fput(file);
 no_file:
-       security_shm_free(shp);
-       ipc_rcu_putref(shp);
+       ipc_rcu_putref(shp, shm_rcu_free);
        return error;
 }
 
 /*
- * 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 +590,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 +703,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 +730,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 +759,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 +776,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 +790,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 +807,7 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
                break;
        default:
                err = -EINVAL;
+               goto out_unlock1;
        }
 
 out_unlock0:
@@ -794,33 +815,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 +846,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 +858,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 +881,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 +915,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 +993,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 +1085,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 +1100,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 +1150,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 +1165,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 +1173,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 +1284,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..7684f41bce76a9b430f04b7e4e77810b48798a42 100644 (file)
  * Jun 2006 - namespaces ssupport
  *            OpenVZ, SWsoft Inc.
  *            Pavel Emelianov <xemul@openvz.org>
+ *
+ * General sysv ipc locking scheme:
+ *     rcu_read_lock()
+ *          obtain the ipc object (kern_ipc_perm) by looking up the id in an idr
+ *         tree.
+ *         - perform initial checks (capabilities, auditing and permission,
+ *           etc).
+ *         - perform read-only operations, such as STAT, INFO commands.
+ *           acquire the ipc lock (kern_ipc_perm.lock) through
+ *           ipc_lock_object()
+ *             - perform data updates, such as SET, RMID commands and
+ *               mechanism-specific operations (semop/semtimedop,
+ *               msgsnd/msgrcv, shmat/shmdt).
+ *         drop the ipc lock, through ipc_unlock_object().
+ *     rcu_read_unlock()
+ *
+ *  The ids->rwsem must be taken when:
+ *     - creating, removing and iterating the existing entries in ipc
+ *       identifier sets.
+ *     - iterating through files under /proc/sysvipc/
+ *
+ *  Note that sems have a special fast path that avoids kern_ipc_perm.lock -
+ *  see sem_lock().
  */
 
 #include <linux/mm.h>
@@ -119,7 +142,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 +197,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 +220,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 +232,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 +270,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 +336,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 +355,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 +400,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 +426,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 +437,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.
  */
  
@@ -465,11 +489,6 @@ void ipc_free(void* ptr, int size)
                kfree(ptr);
 }
 
-struct ipc_rcu {
-       struct rcu_head rcu;
-       atomic_t refcount;
-} ____cacheline_aligned_in_smp;
-
 /**
  *     ipc_rcu_alloc   -       allocate ipc and rcu space 
  *     @size: size desired
@@ -496,27 +515,24 @@ int ipc_rcu_getref(void *ptr)
        return atomic_inc_not_zero(&p->refcount);
 }
 
-/**
- * ipc_schedule_free - free ipc + rcu space
- * @head: RCU callback structure for queued work
- */
-static void ipc_schedule_free(struct rcu_head *head)
-{
-       vfree(container_of(head, struct ipc_rcu, rcu));
-}
-
-void ipc_rcu_putref(void *ptr)
+void ipc_rcu_putref(void *ptr, void (*func)(struct rcu_head *head))
 {
        struct ipc_rcu *p = ((struct ipc_rcu *)ptr) - 1;
 
        if (!atomic_dec_and_test(&p->refcount))
                return;
 
-       if (is_vmalloc_addr(ptr)) {
-               call_rcu(&p->rcu, ipc_schedule_free);
-       } else {
-               kfree_rcu(p, rcu);
-       }
+       call_rcu(&p->rcu, func);
+}
+
+void ipc_rcu_free(struct rcu_head *head)
+{
+       struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
+
+       if (is_vmalloc_addr(p))
+               vfree(p);
+       else
+               kfree(p);
 }
 
 /**
@@ -621,7 +637,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 +693,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 +733,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 +746,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 +830,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 +869,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 +896,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..f2f5036f2eeda9794bc545ac8045db3c56f7d425 100644 (file)
@@ -47,6 +47,13 @@ static inline void msg_exit_ns(struct ipc_namespace *ns) { }
 static inline void shm_exit_ns(struct ipc_namespace *ns) { }
 #endif
 
+struct ipc_rcu {
+       struct rcu_head rcu;
+       atomic_t refcount;
+} ____cacheline_aligned_in_smp;
+
+#define ipc_rcu_to_struct(p)  ((void *)(p+1))
+
 /*
  * Structure that holds the parameters needed by the ipc operations
  * (see after)
@@ -94,10 +101,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. */
@@ -120,7 +127,8 @@ void ipc_free(void* ptr, int size);
  */
 void* ipc_rcu_alloc(int size);
 int ipc_rcu_getref(void *ptr);
-void ipc_rcu_putref(void *ptr);
+void ipc_rcu_putref(void *ptr, void (*func)(struct rcu_head *head));
+void ipc_rcu_free(struct rcu_head *head);
 
 struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
 struct kern_ipc_perm *ipc_obtain_object(struct ipc_ids *ids, int id);
@@ -131,9 +139,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 +179,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 91e53d04b6a9e8841e697dcb290f1206468da21a..7b0e23a740ce345987c33f9e012302c24de0f4db 100644 (file)
@@ -1117,9 +1117,10 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
 
                        sleep_time = timeout_start + audit_backlog_wait_time -
                                        jiffies;
-                       if ((long)sleep_time > 0)
+                       if ((long)sleep_time > 0) {
                                wait_for_auditd(sleep_time);
-                       continue;
+                               continue;
+                       }
                }
                if (audit_rate_check() && printk_ratelimit())
                        printk(KERN_WARNING
index f6c2ce5701e1c3c723d03e3d917c62f584c3a074..4e66bf9275b03edf3c62e0e350afc5248f2b00b8 100644 (file)
@@ -432,18 +432,6 @@ bool capable(int cap)
 }
 EXPORT_SYMBOL(capable);
 
-/**
- * nsown_capable - Check superior capability to one's own user_ns
- * @cap: The capability in question
- *
- * Return true if the current task has the given superior capability
- * targeted at its own user namespace.
- */
-bool nsown_capable(int cap)
-{
-       return ns_capable(current_user_ns(), cap);
-}
-
 /**
  * inode_capable - Check superior capability over inode
  * @inode: The inode in question
@@ -464,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..8bd9cfdc70d7bc020dbc19a05813e2e49443b8e8 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>
 
@@ -2038,7 +2039,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
 
                /* @tsk either already exited or can't exit until the end */
                if (tsk->flags & PF_EXITING)
-                       continue;
+                       goto next;
 
                /* as per above, nr_threads may decrease, but not increase. */
                BUG_ON(i >= group_size);
@@ -2046,7 +2047,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
                ent.cgrp = task_cgroup_from_root(tsk, root);
                /* nothing to do if this task is already in the cgroup */
                if (ent.cgrp == cgrp)
-                       continue;
+                       goto next;
                /*
                 * saying GFP_ATOMIC has no effect here because we did prealloc
                 * earlier, but it's good form to communicate our expectations.
@@ -2054,7 +2055,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
                retval = flex_array_put(group, i, &ent, GFP_ATOMIC);
                BUG_ON(retval != 0);
                i++;
-
+       next:
                if (!threadgroup)
                        break;
        } while_each_thread(leader, tsk);
@@ -3187,11 +3188,9 @@ css_next_descendant_post(struct cgroup_subsys_state *pos,
 
        WARN_ON_ONCE(!rcu_read_lock_held());
 
-       /* if first iteration, visit the leftmost descendant */
-       if (!pos) {
-               next = css_leftmost_descendant(root);
-               return next != root ? next : NULL;
-       }
+       /* if first iteration, visit leftmost descendant which may be @root */
+       if (!pos)
+               return css_leftmost_descendant(root);
 
        /* if we visited @root, we're done */
        if (pos == root)
@@ -4034,8 +4033,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 +4057,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 +4102,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 +4120,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 247091bf0587a479594776be800db9164a10ae8b..859c8dfd78a1a5b296dd5c6c23d741e7a4c1e8cd 100644 (file)
@@ -50,6 +50,15 @@ void context_tracking_user_enter(void)
 {
        unsigned long flags;
 
+       /*
+        * Repeat the user_enter() check here because some archs may be calling
+        * this from asm and if no CPU needs context tracking, they shouldn't
+        * go further. Repeat the check here until they support the static key
+        * check.
+        */
+       if (!static_key_false(&context_tracking_enabled))
+               return;
+
        /*
         * Some contexts may involve an exception occuring in an irq,
         * leading to that nesting:
@@ -151,6 +160,9 @@ void context_tracking_user_exit(void)
 {
        unsigned long flags;
 
+       if (!static_key_false(&context_tracking_enabled))
+               return;
+
        if (in_interrupt())
                return;
 
index 2207efc941d1da66efe03d0db33f40e6b4670307..d49a9d29334cc4d67c24bad9814221a0371a6350 100644 (file)
@@ -3660,6 +3660,26 @@ static void calc_timer_values(struct perf_event *event,
        *running = ctx_time - event->tstamp_running;
 }
 
+static void perf_event_init_userpage(struct perf_event *event)
+{
+       struct perf_event_mmap_page *userpg;
+       struct ring_buffer *rb;
+
+       rcu_read_lock();
+       rb = rcu_dereference(event->rb);
+       if (!rb)
+               goto unlock;
+
+       userpg = rb->user_page;
+
+       /* Allow new userspace to detect that bit 0 is deprecated */
+       userpg->cap_bit0_is_deprecated = 1;
+       userpg->size = offsetof(struct perf_event_mmap_page, __reserved);
+
+unlock:
+       rcu_read_unlock();
+}
+
 void __weak arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
 {
 }
@@ -4044,6 +4064,7 @@ again:
        ring_buffer_attach(event, rb);
        rcu_assign_pointer(event->rb, rb);
 
+       perf_event_init_userpage(event);
        perf_event_update_userpage(event);
 
 unlock:
@@ -5039,6 +5060,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);
@@ -7212,15 +7234,15 @@ void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu)
                perf_remove_from_context(event);
                unaccount_event_cpu(event, src_cpu);
                put_ctx(src_ctx);
-               list_add(&event->event_entry, &events);
+               list_add(&event->migrate_entry, &events);
        }
        mutex_unlock(&src_ctx->mutex);
 
        synchronize_rcu();
 
        mutex_lock(&dst_ctx->mutex);
-       list_for_each_entry_safe(event, tmp, &events, event_entry) {
-               list_del(&event->event_entry);
+       list_for_each_entry_safe(event, tmp, &events, migrate_entry) {
+               list_del(&event->migrate_entry);
                if (event->state >= PERF_EVENT_STATE_OFF)
                        event->state = PERF_EVENT_STATE_INACTIVE;
                account_event_cpu(event, dst_cpu);
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 bf46287c91a45cc4f52d348d4be503e1ecf94620..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
@@ -1824,11 +1815,6 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
         */
        if (unshare_flags & CLONE_NEWUSER)
                unshare_flags |= CLONE_THREAD | CLONE_FS;
-       /*
-        * If unsharing a pid namespace must also unshare the thread.
-        */
-       if (unshare_flags & CLONE_NEWPID)
-               unshare_flags |= CLONE_THREAD;
        /*
         * If unsharing a thread from a thread group, must also unshare vm.
         */
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 6b2588dd04ff20fb89995394f9c530a2613fbb83..90cf1c38c8ea8cd425f09a078e2e334db6d675cc 100644 (file)
@@ -233,7 +233,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
        struct group_info *group_info;
        int retval;
 
-       if (!nsown_capable(CAP_SETGID))
+       if (!ns_capable(current_user_ns(), CAP_SETGID))
                return -EPERM;
        if ((unsigned)gidsetsize > NGROUPS_MAX)
                return -EINVAL;
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 fb326365b69466158b03b726e53c4fe15448fa89..b086006c59e7c6957a51984a3ec101ea2db8525d 100644 (file)
@@ -571,6 +571,10 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
        DECLARE_COMPLETION_ONSTACK(done);
        int retval = 0;
 
+       if (!sub_info->path) {
+               call_usermodehelper_freeinfo(sub_info);
+               return -EINVAL;
+       }
        helper_lock();
        if (!khelper_wq || usermodehelper_disabled) {
                retval = -EBUSY;
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 997cbb951a3bd07783e02e5354c3ac369ae4e356..8e7811086b826cbc42b6be594d2fc605fee0b84d 100644 (file)
@@ -126,22 +126,16 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
        struct nsproxy *old_ns = tsk->nsproxy;
        struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);
        struct nsproxy *new_ns;
-       int err = 0;
 
-       if (!old_ns)
+       if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
+                             CLONE_NEWPID | CLONE_NEWNET)))) {
+               get_nsproxy(old_ns);
                return 0;
-
-       get_nsproxy(old_ns);
-
-       if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-                               CLONE_NEWPID | CLONE_NEWNET)))
-               return 0;
-
-       if (!ns_capable(user_ns, CAP_SYS_ADMIN)) {
-               err = -EPERM;
-               goto out;
        }
 
+       if (!ns_capable(user_ns, CAP_SYS_ADMIN))
+               return -EPERM;
+
        /*
         * CLONE_NEWIPC must detach from the undolist: after switching
         * to a new ipc namespace, the semaphore arrays from the old
@@ -149,22 +143,16 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
         * means share undolist with parent, so we must forbid using
         * it along with CLONE_NEWIPC.
         */
-       if ((flags & CLONE_NEWIPC) && (flags & CLONE_SYSVSEM)) {
-               err = -EINVAL;
-               goto out;
-       }
+       if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) ==
+               (CLONE_NEWIPC | CLONE_SYSVSEM)) 
+               return -EINVAL;
 
        new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs);
-       if (IS_ERR(new_ns)) {
-               err = PTR_ERR(new_ns);
-               goto out;
-       }
+       if (IS_ERR(new_ns))
+               return  PTR_ERR(new_ns);
 
        tsk->nsproxy = new_ns;
-
-out:
-       put_nsproxy(old_ns);
-       return err;
+       return 0;
 }
 
 void free_nsproxy(struct nsproxy *ns)
index 072f4ee4eb893a5341942146775c2ce9fcc1dbc8..07af2c95dcfeea37f855db214e8e3405274bddb6 100644 (file)
@@ -846,6 +846,8 @@ static int padata_cpu_callback(struct notifier_block *nfb,
        switch (action) {
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
+       case CPU_DOWN_FAILED:
+       case CPU_DOWN_FAILED_FROZEN:
                if (!pinst_has_cpu(pinst, cpu))
                        break;
                mutex_lock(&pinst->lock);
@@ -857,6 +859,8 @@ static int padata_cpu_callback(struct notifier_block *nfb,
 
        case CPU_DOWN_PREPARE:
        case CPU_DOWN_PREPARE_FROZEN:
+       case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
                if (!pinst_has_cpu(pinst, cpu))
                        break;
                mutex_lock(&pinst->lock);
@@ -865,22 +869,6 @@ static int padata_cpu_callback(struct notifier_block *nfb,
                if (err)
                        return notifier_from_errno(err);
                break;
-
-       case CPU_UP_CANCELED:
-       case CPU_UP_CANCELED_FROZEN:
-               if (!pinst_has_cpu(pinst, cpu))
-                       break;
-               mutex_lock(&pinst->lock);
-               __padata_remove_cpu(pinst, cpu);
-               mutex_unlock(&pinst->lock);
-
-       case CPU_DOWN_FAILED:
-       case CPU_DOWN_FAILED_FROZEN:
-               if (!pinst_has_cpu(pinst, cpu))
-                       break;
-               mutex_lock(&pinst->lock);
-               __padata_add_cpu(pinst, cpu);
-               mutex_unlock(&pinst->lock);
        }
 
        return NOTIFY_OK;
@@ -1086,18 +1074,18 @@ struct padata_instance *padata_alloc(struct workqueue_struct *wq,
 
        pinst->flags = 0;
 
-#ifdef CONFIG_HOTPLUG_CPU
-       pinst->cpu_notifier.notifier_call = padata_cpu_callback;
-       pinst->cpu_notifier.priority = 0;
-       register_hotcpu_notifier(&pinst->cpu_notifier);
-#endif
-
        put_online_cpus();
 
        BLOCKING_INIT_NOTIFIER_HEAD(&pinst->cpumask_change_notifier);
        kobject_init(&pinst->kobj, &padata_attr_type);
        mutex_init(&pinst->lock);
 
+#ifdef CONFIG_HOTPLUG_CPU
+       pinst->cpu_notifier.notifier_call = padata_cpu_callback;
+       pinst->cpu_notifier.priority = 0;
+       register_hotcpu_notifier(&pinst->cpu_notifier);
+#endif
+
        return pinst;
 
 err_free_masks:
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..c00d5b502aa487de0f09117c21dfa12eb8923e0c 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, kstrtol);
+STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, kstrtoul);
+STANDARD_PARAM_DEF(int, int, "%i", long, kstrtol);
+STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, kstrtoul);
+STANDARD_PARAM_DEF(long, long, "%li", long, kstrtol);
+STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, kstrtoul);
 
 int param_set_charp(const char *val, const struct kernel_param *kp)
 {
index 66505c1dfc516f3985e2072029152291cd0bedf9..9b9a26698144e126486e162955e49561514b1ce8 100644 (file)
@@ -265,6 +265,7 @@ void free_pid(struct pid *pid)
                struct pid_namespace *ns = upid->ns;
                hlist_del_rcu(&upid->pid_chain);
                switch(--ns->nr_hashed) {
+               case 2:
                case 1:
                        /* When all that is left in the pid namespace
                         * is the reaper wake up the reaper.  The reaper
@@ -272,6 +273,11 @@ void free_pid(struct pid *pid)
                         */
                        wake_up_process(ns->child_reaper);
                        break;
+               case PIDNS_HASH_ADDING:
+                       /* Handle a fork failure of the first process */
+                       WARN_ON(ns->child_reaper);
+                       ns->nr_hashed = 0;
+                       /* fall through */
                case 0:
                        schedule_work(&ns->proc_work);
                        break;
index 601bb361c235a9ff28327a92b1e1a4387d128d0f..42086551a24a19d9563148ee1810e30e68cccbbe 100644 (file)
@@ -329,7 +329,7 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns)
        struct pid_namespace *ancestor, *new = ns;
 
        if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) ||
-           !nsown_capable(CAP_SYS_ADMIN))
+           !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
                return -EPERM;
 
        /*
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..98c3b34a4cffcedeae812de0ddc947f874cef839 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)
@@ -743,7 +743,10 @@ int create_basic_memory_bitmaps(void)
        struct memory_bitmap *bm1, *bm2;
        int error = 0;
 
-       BUG_ON(forbidden_pages_map || free_pages_map);
+       if (forbidden_pages_map && free_pages_map)
+               return 0;
+       else
+               BUG_ON(forbidden_pages_map || free_pages_map);
 
        bm1 = kzalloc(sizeof(struct memory_bitmap), GFP_KERNEL);
        if (!bm1)
@@ -884,7 +887,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 +951,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 +1044,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 +1096,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 +1758,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..957f06164ad1004b0050dbdcb7563c91c3755e55 100644 (file)
@@ -39,6 +39,7 @@ static struct snapshot_data {
        char frozen;
        char ready;
        char platform_support;
+       bool free_bitmaps;
 } snapshot_state;
 
 atomic_t snapshot_device_available = ATOMIC_INIT(1);
@@ -60,11 +61,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;
@@ -87,13 +83,16 @@ static int snapshot_open(struct inode *inode, struct file *filp)
                data->swap = -1;
                data->mode = O_WRONLY;
                error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+               if (!error) {
+                       error = create_basic_memory_bitmaps();
+                       data->free_bitmaps = !error;
+               }
                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,12 +110,14 @@ 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();
+       } else if (data->free_bitmaps) {
+               free_basic_memory_bitmaps();
        }
        pm_notifier_call_chain(data->mode == O_RDONLY ?
                        PM_POST_HIBERNATION : PM_POST_RESTORE);
@@ -207,6 +208,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 +222,23 @@ 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();
+               data->free_bitmaps = false;
                thaw_processes();
                data->frozen = 0;
                break;
@@ -371,6 +382,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 269ed9384cc4284e9cf6043bd00667ea582c4369..f813b3474646c5b320a19d9a8997349bdd14d68e 100644 (file)
@@ -32,7 +32,14 @@ EXPORT_SYMBOL(cad_pid);
 #endif
 enum reboot_mode reboot_mode DEFAULT_REBOOT_MODE;
 
-int reboot_default;
+/*
+ * This variable is used privately to keep track of whether or not
+ * reboot_type is still set to its default value (i.e., reboot= hasn't
+ * been set on the command line).  This is needed so that we can
+ * suppress DMI scanning for reboot quirks.  Without it, it's
+ * impossible to override a faulty reboot quirk without recompiling.
+ */
+int reboot_default = 1;
 int reboot_cpu;
 enum reboot_type reboot_type = BOOT_ACPI;
 int reboot_force;
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..7c70201fbc61aef012d5b2536600d898602bab0a 100644 (file)
@@ -4242,7 +4242,7 @@ static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq)
        }
 
        if (!se) {
-               cfs_rq->h_load = rq->avg.load_avg_contrib;
+               cfs_rq->h_load = cfs_rq->runnable_load_avg;
                cfs_rq->last_h_load_update = now;
        }
 
@@ -4823,8 +4823,8 @@ void fix_small_imbalance(struct lb_env *env, struct sd_lb_stats *sds)
                (busiest->load_per_task * SCHED_POWER_SCALE) /
                busiest->group_power;
 
-       if (busiest->avg_load - local->avg_load + scaled_busy_load_per_task >=
-           (scaled_busy_load_per_task * imbn)) {
+       if (busiest->avg_load + scaled_busy_load_per_task >=
+           local->avg_load + (scaled_busy_load_per_task * imbn)) {
                env->imbalance = busiest->load_per_task;
                return;
        }
@@ -4896,7 +4896,8 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
         * max load less than avg load(as we skip the groups at or below
         * its cpu_power, while calculating max_load..)
         */
-       if (busiest->avg_load < sds->avg_load) {
+       if (busiest->avg_load <= sds->avg_load ||
+           local->avg_load >= sds->avg_load) {
                env->imbalance = 0;
                return fix_small_imbalance(env, sds);
        }
@@ -5151,7 +5152,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 +5929,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..d7d498d8cc4f8185954a220c66071cbc5761b917 100644 (file)
@@ -328,10 +328,19 @@ void irq_enter(void)
 
 static inline void invoke_softirq(void)
 {
-       if (!force_irqthreads)
-               __do_softirq();
-       else
+       if (!force_irqthreads) {
+               /*
+                * We can safely execute softirq on the current stack if
+                * it is the irq stack, because it should be near empty
+                * at this stage. But we have no way to know if the arch
+                * calls irq_exit() on the irq stack. So call softirq
+                * in its own stack to prevent from any overrun on top
+                * of a potentially deep task stack.
+                */
+               do_softirq();
+       } else {
                wakeup_softirqd();
+       }
 }
 
 static inline void tick_irq_exit(void)
@@ -876,7 +885,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 +894,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 771129b299f8865d176f233e1f14c290da8c89c8..c18ecca575b42e0dcc9e12e2fc5c279983d9eb57 100644 (file)
@@ -337,7 +337,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
        if (rgid != (gid_t) -1) {
                if (gid_eq(old->gid, krgid) ||
                    gid_eq(old->egid, krgid) ||
-                   nsown_capable(CAP_SETGID))
+                   ns_capable(old->user_ns, CAP_SETGID))
                        new->gid = krgid;
                else
                        goto error;
@@ -346,7 +346,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
                if (gid_eq(old->gid, kegid) ||
                    gid_eq(old->egid, kegid) ||
                    gid_eq(old->sgid, kegid) ||
-                   nsown_capable(CAP_SETGID))
+                   ns_capable(old->user_ns, CAP_SETGID))
                        new->egid = kegid;
                else
                        goto error;
@@ -387,7 +387,7 @@ SYSCALL_DEFINE1(setgid, gid_t, gid)
        old = current_cred();
 
        retval = -EPERM;
-       if (nsown_capable(CAP_SETGID))
+       if (ns_capable(old->user_ns, CAP_SETGID))
                new->gid = new->egid = new->sgid = new->fsgid = kgid;
        else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid))
                new->egid = new->fsgid = kgid;
@@ -471,7 +471,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
                new->uid = kruid;
                if (!uid_eq(old->uid, kruid) &&
                    !uid_eq(old->euid, kruid) &&
-                   !nsown_capable(CAP_SETUID))
+                   !ns_capable(old->user_ns, CAP_SETUID))
                        goto error;
        }
 
@@ -480,7 +480,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
                if (!uid_eq(old->uid, keuid) &&
                    !uid_eq(old->euid, keuid) &&
                    !uid_eq(old->suid, keuid) &&
-                   !nsown_capable(CAP_SETUID))
+                   !ns_capable(old->user_ns, CAP_SETUID))
                        goto error;
        }
 
@@ -534,7 +534,7 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
        old = current_cred();
 
        retval = -EPERM;
-       if (nsown_capable(CAP_SETUID)) {
+       if (ns_capable(old->user_ns, CAP_SETUID)) {
                new->suid = new->uid = kuid;
                if (!uid_eq(kuid, old->uid)) {
                        retval = set_user(new);
@@ -591,7 +591,7 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
        old = current_cred();
 
        retval = -EPERM;
-       if (!nsown_capable(CAP_SETUID)) {
+       if (!ns_capable(old->user_ns, CAP_SETUID)) {
                if (ruid != (uid_t) -1        && !uid_eq(kruid, old->uid) &&
                    !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid))
                        goto error;
@@ -673,7 +673,7 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
        old = current_cred();
 
        retval = -EPERM;
-       if (!nsown_capable(CAP_SETGID)) {
+       if (!ns_capable(old->user_ns, CAP_SETGID)) {
                if (rgid != (gid_t) -1        && !gid_eq(krgid, old->gid) &&
                    !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid))
                        goto error;
@@ -744,7 +744,7 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
 
        if (uid_eq(kuid, old->uid)  || uid_eq(kuid, old->euid)  ||
            uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) ||
-           nsown_capable(CAP_SETUID)) {
+           ns_capable(old->user_ns, CAP_SETUID)) {
                if (!uid_eq(kuid, old->fsuid)) {
                        new->fsuid = kuid;
                        if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
@@ -783,7 +783,7 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
 
        if (gid_eq(kgid, old->gid)  || gid_eq(kgid, old->egid)  ||
            gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) ||
-           nsown_capable(CAP_SETGID)) {
+           ns_capable(old->user_ns, CAP_SETGID)) {
                if (!gid_eq(kgid, old->fsgid)) {
                        new->fsgid = kgid;
                        goto change_okay;
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 f6c83d7ef0006fffe3cc9811b736c513c1b8f6f1..602e5bbbceff51ef47d4a22d2e3a51e34a88cfd5 100644 (file)
@@ -176,7 +176,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist)
        struct group_info *group_info;
        int retval;
 
-       if (!nsown_capable(CAP_SETGID))
+       if (!ns_capable(current_user_ns(), CAP_SETGID))
                return -EPERM;
        if ((unsigned)gidsetsize > NGROUPS_MAX)
                return -EINVAL;
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 69b4c3d48cdee20fc94be4d2869e2e330ba0a7b2..5bbb91988e69278f2cd012896db29688c9234476 100644 (file)
@@ -51,8 +51,6 @@ struct user_namespace init_user_ns = {
        .owner = GLOBAL_ROOT_UID,
        .group = GLOBAL_ROOT_GID,
        .proc_inum = PROC_USER_INIT_INO,
-       .may_mount_sysfs = true,
-       .may_mount_proc = true,
 };
 EXPORT_SYMBOL_GPL(init_user_ns);
 
index 9064b919a4066fe9fca676581479e9162de56717..13fb1134ba582e49c8aa3643feada72a2b0dae8b 100644 (file)
@@ -101,8 +101,6 @@ int create_user_ns(struct cred *new)
 
        set_cred_user_ns(new, ns);
 
-       update_mnt_policy(ns);
-
        return 0;
 }
 
index 2fc8576efaa8e7a5201d9334f6fb8452cc14226a..fd393124e507f15f6d366a0f41e4808b81c64934 100644 (file)
@@ -114,7 +114,7 @@ static int utsns_install(struct nsproxy *nsproxy, void *new)
        struct uts_namespace *ns = new;
 
        if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
-           !nsown_capable(CAP_SYS_ADMIN))
+           !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
                return -EPERM;
 
        get_uts_ns(ns);
index 51c4f34d258ea397266e0dd1a96a16436415a38f..4431610f049ac77888adefe3a335d47d4d232939 100644 (file)
@@ -486,7 +486,52 @@ static struct smp_hotplug_thread watchdog_threads = {
        .unpark                 = watchdog_enable,
 };
 
-static int watchdog_enable_all_cpus(void)
+static void restart_watchdog_hrtimer(void *info)
+{
+       struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
+       int ret;
+
+       /*
+        * No need to cancel and restart hrtimer if it is currently executing
+        * because it will reprogram itself with the new period now.
+        * We should never see it unqueued here because we are running per-cpu
+        * with interrupts disabled.
+        */
+       ret = hrtimer_try_to_cancel(hrtimer);
+       if (ret == 1)
+               hrtimer_start(hrtimer, ns_to_ktime(sample_period),
+                               HRTIMER_MODE_REL_PINNED);
+}
+
+static void update_timers(int cpu)
+{
+       struct call_single_data data = {.func = restart_watchdog_hrtimer};
+       /*
+        * Make sure that perf event counter will adopt to a new
+        * sampling period. Updating the sampling period directly would
+        * be much nicer but we do not have an API for that now so
+        * let's use a big hammer.
+        * Hrtimer will adopt the new period on the next tick but this
+        * might be late already so we have to restart the timer as well.
+        */
+       watchdog_nmi_disable(cpu);
+       __smp_call_function_single(cpu, &data, 1);
+       watchdog_nmi_enable(cpu);
+}
+
+static void update_timers_all_cpus(void)
+{
+       int cpu;
+
+       get_online_cpus();
+       preempt_disable();
+       for_each_online_cpu(cpu)
+               update_timers(cpu);
+       preempt_enable();
+       put_online_cpus();
+}
+
+static int watchdog_enable_all_cpus(bool sample_period_changed)
 {
        int err = 0;
 
@@ -496,6 +541,8 @@ static int watchdog_enable_all_cpus(void)
                        pr_err("Failed to create watchdog threads, disabled\n");
                else
                        watchdog_running = 1;
+       } else if (sample_period_changed) {
+               update_timers_all_cpus();
        }
 
        return err;
@@ -520,13 +567,15 @@ int proc_dowatchdog(struct ctl_table *table, int write,
                    void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        int err, old_thresh, old_enabled;
+       static DEFINE_MUTEX(watchdog_proc_mutex);
 
+       mutex_lock(&watchdog_proc_mutex);
        old_thresh = ACCESS_ONCE(watchdog_thresh);
        old_enabled = ACCESS_ONCE(watchdog_user_enabled);
 
        err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
        if (err || !write)
-               return err;
+               goto out;
 
        set_sample_period();
        /*
@@ -535,7 +584,7 @@ int proc_dowatchdog(struct ctl_table *table, int write,
         * watchdog_*_all_cpus() function takes care of this.
         */
        if (watchdog_user_enabled && watchdog_thresh)
-               err = watchdog_enable_all_cpus();
+               err = watchdog_enable_all_cpus(old_thresh != watchdog_thresh);
        else
                watchdog_disable_all_cpus();
 
@@ -544,7 +593,8 @@ int proc_dowatchdog(struct ctl_table *table, int write,
                watchdog_thresh = old_thresh;
                watchdog_user_enabled = old_enabled;
        }
-
+out:
+       mutex_unlock(&watchdog_proc_mutex);
        return err;
 }
 #endif /* CONFIG_SYSCTL */
@@ -554,5 +604,5 @@ void __init lockup_detector_init(void)
        set_sample_period();
 
        if (watchdog_user_enabled)
-               watchdog_enable_all_cpus();
+               watchdog_enable_all_cpus(false);
 }
index 65561716c16c4345a8e9ab00db9655ffa95a62de..b3c8be0da17f8472429ad79787c76d42fa62eb02 100644 (file)
@@ -76,6 +76,8 @@ config CRC16
 
 config CRC_T10DIF
        tristate "CRC calculation for the T10 Data Integrity Field"
+       select CRYPTO
+       select CRYPTO_CRCT10DIF
        help
          This option is only needed if a module that's not in the
          kernel tree needs to calculate CRC checks for use with the
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 fbbd66ed86cde5ed7724ed8f17986cdf1a37edaa..dfe6ec17c0a5fa774ec34d23de696be7b99a6182 100644 (file)
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/crc-t10dif.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <crypto/hash.h>
+#include <linux/static_key.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
-};
+static struct crypto_shash *crct10dif_tfm;
+static struct static_key crct10dif_fallback __read_mostly;
 
 __u16 crc_t10dif(const unsigned char *buffer, size_t len)
 {
-       __u16 crc = 0;
-       unsigned int i;
+       struct {
+               struct shash_desc shash;
+               char ctx[2];
+       } 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;
 
-       for (i = 0 ; i < len ; i++)
-               crc = (crc << 8) ^ t10_dif_crc_table[((crc >> 8) ^ buffer[i]) & 0xff];
+       err = crypto_shash_update(&desc.shash, buffer, len);
+       BUG_ON(err);
 
-       return crc;
+       return *(__u16 *)desc.ctx;
 }
 EXPORT_SYMBOL(crc_t10dif);
 
+static int __init crc_t10dif_mod_init(void)
+{
+       crct10dif_tfm = crypto_alloc_shash("crct10dif", 0, 0);
+       if (IS_ERR(crct10dif_tfm)) {
+               static_key_slow_inc(&crct10dif_fallback);
+               crct10dif_tfm = NULL;
+       }
+       return 0;
+}
+
+static void __exit crc_t10dif_mod_fini(void)
+{
+       crypto_free_shash(crct10dif_tfm);
+}
+
+module_init(crc_t10dif_mod_init);
+module_exit(crc_t10dif_mod_fini);
+
 MODULE_DESCRIPTION("T10 DIF CRC calculation");
 MODULE_LICENSE("GPL");
+MODULE_SOFTDEP("pre: crct10dif");
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 3f0494c9d57aaf24cbbea90231e010d1d06f3e04..8499c810909a58ae100b7db96a01ea74b5c14948 100644 (file)
@@ -14,6 +14,8 @@
 
 const char hex_asc[] = "0123456789abcdef";
 EXPORT_SYMBOL(hex_asc);
+const char hex_asc_upper[] = "0123456789ABCDEF";
+EXPORT_SYMBOL(hex_asc_upper);
 
 /**
  * hex_to_bin - convert a hex digit to its real value
index 1d46c151a4aea8ca741623931bba5d737ac5bc64..084f7b18d0c0a722e215dce8d14dcda0e6ba78d8 100644 (file)
@@ -592,7 +592,7 @@ static void kobject_release(struct kref *kref)
 {
        struct kobject *kobj = container_of(kref, struct kobject, kref);
 #ifdef CONFIG_DEBUG_KOBJECT_RELEASE
-       pr_debug("kobject: '%s' (%p): %s, parent %p (delayed)\n",
+       pr_info("kobject: '%s' (%p): %s, parent %p (delayed)\n",
                 kobject_name(kobj), kobj, __func__, kobj->parent);
        INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup);
        schedule_delayed_work(&kobj->release, HZ);
@@ -931,6 +931,18 @@ const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj)
        return kobj_child_ns_ops(kobj->parent);
 }
 
+bool kobj_ns_current_may_mount(enum kobj_ns_type type)
+{
+       bool may_mount = true;
+
+       spin_lock(&kobj_ns_type_lock);
+       if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
+           kobj_ns_ops_tbl[type])
+               may_mount = kobj_ns_ops_tbl[type]->current_may_mount();
+       spin_unlock(&kobj_ns_type_lock);
+
+       return may_mount;
+}
 
 void *kobj_ns_grab_current(enum kobj_ns_type type)
 {
index 9d76f404ce9a6589e7e5b98733d7317b0ad5bb1a..6f9d434c1521eab9ca0b2821d10936af55f2b703 100644 (file)
@@ -3,6 +3,22 @@
 
 #ifdef CONFIG_CMPXCHG_LOCKREF
 
+/*
+ * Allow weakly-ordered memory architectures to provide barrier-less
+ * cmpxchg semantics for lockref updates.
+ */
+#ifndef cmpxchg64_relaxed
+# define cmpxchg64_relaxed cmpxchg64
+#endif
+
+/*
+ * Allow architectures to override the default cpu_relax() within CMPXCHG_LOOP.
+ * This is useful for architectures with an expensive cpu_relax().
+ */
+#ifndef arch_mutex_cpu_relax
+# define arch_mutex_cpu_relax() cpu_relax()
+#endif
+
 /*
  * Note that the "cmpxchg()" reloads the "old" value for the
  * failure case.
        while (likely(arch_spin_value_unlocked(old.lock.rlock.raw_lock))) {     \
                struct lockref new = old, prev = old;                           \
                CODE                                                            \
-               old.lock_count = cmpxchg(&lockref->lock_count,                  \
-                                        old.lock_count, new.lock_count);       \
+               old.lock_count = cmpxchg64_relaxed(&lockref->lock_count,        \
+                                                  old.lock_count,              \
+                                                  new.lock_count);             \
                if (likely(old.lock_count == prev.lock_count)) {                \
                        SUCCESS;                                                \
                }                                                               \
-               cpu_relax();                                                    \
+               arch_mutex_cpu_relax();                                         \
        }                                                                       \
 } while (0)
 
@@ -31,7 +48,7 @@
 
 /**
  * lockref_get - Increments reference count unconditionally
- * @lockcnt: pointer to lockref structure
+ * @lockref: pointer to lockref structure
  *
  * This operation is only valid if you already hold a reference
  * to the object, so you know the count cannot be zero.
@@ -52,7 +69,7 @@ EXPORT_SYMBOL(lockref_get);
 
 /**
  * lockref_get_not_zero - Increments count unless the count is 0
- * @lockcnt: pointer to lockref structure
+ * @lockref: pointer to lockref structure
  * Return: 1 if count updated successfully or 0 if count was zero
  */
 int lockref_get_not_zero(struct lockref *lockref)
@@ -80,7 +97,7 @@ EXPORT_SYMBOL(lockref_get_not_zero);
 
 /**
  * lockref_get_or_lock - Increments count unless the count is 0
- * @lockcnt: pointer to lockref structure
+ * @lockref: pointer to lockref structure
  * Return: 1 if count updated successfully or 0 if count was zero
  * and we got the lock instead.
  */
@@ -105,7 +122,7 @@ EXPORT_SYMBOL(lockref_get_or_lock);
 
 /**
  * lockref_put_or_lock - decrements count unless count <= 1 before decrement
- * @lockcnt: pointer to lockref structure
+ * @lockref: pointer to lockref structure
  * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken
  */
 int lockref_put_or_lock(struct lockref *lockref)
@@ -126,3 +143,41 @@ int lockref_put_or_lock(struct lockref *lockref)
        return 1;
 }
 EXPORT_SYMBOL(lockref_put_or_lock);
+
+/**
+ * lockref_mark_dead - mark lockref dead
+ * @lockref: pointer to lockref structure
+ */
+void lockref_mark_dead(struct lockref *lockref)
+{
+       assert_spin_locked(&lockref->lock);
+       lockref->count = -128;
+}
+
+/**
+ * lockref_get_not_dead - Increments count unless the ref is dead
+ * @lockref: pointer to lockref structure
+ * Return: 1 if count updated successfully or 0 if lockref was dead
+ */
+int lockref_get_not_dead(struct lockref *lockref)
+{
+       int retval;
+
+       CMPXCHG_LOOP(
+               new.count++;
+               if ((int)old.count < 0)
+                       return 0;
+       ,
+               return 1;
+       );
+
+       spin_lock(&lockref->lock);
+       retval = 0;
+       if ((int) lockref->count >= 0) {
+               lockref->count++;
+               retval = 1;
+       }
+       spin_unlock(&lockref->lock);
+       return retval;
+}
+EXPORT_SYMBOL(lockref_get_not_dead);
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;
index 7deeb6297a483d7272acb30c4f3b0c0d6b0e76b3..1a53d497a8c53ae460686af6107531c4161eae53 100644 (file)
@@ -53,6 +53,7 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release)
        ref->release = release;
        return 0;
 }
+EXPORT_SYMBOL_GPL(percpu_ref_init);
 
 /**
  * percpu_ref_cancel_init - cancel percpu_ref_init()
@@ -84,6 +85,7 @@ void percpu_ref_cancel_init(struct percpu_ref *ref)
                free_percpu(ref->pcpu_count);
        }
 }
+EXPORT_SYMBOL_GPL(percpu_ref_cancel_init);
 
 static void percpu_ref_kill_rcu(struct rcu_head *rcu)
 {
@@ -156,3 +158,4 @@ void percpu_ref_kill_and_confirm(struct percpu_ref *ref,
 
        call_rcu_sched(&ref->rcu, percpu_ref_kill_rcu);
 }
+EXPORT_SYMBOL_GPL(percpu_ref_kill_and_confirm);
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..394838f489ebae1b9d00660af54ceac857538653 100644 (file)
@@ -183,7 +183,7 @@ config MEMORY_HOTPLUG_SPARSE
 config MEMORY_HOTREMOVE
        bool "Allow for memory hot remove"
        select MEMORY_ISOLATION
-       select HAVE_BOOTMEM_INFO_NODE if X86_64
+       select HAVE_BOOTMEM_INFO_NODE if (X86_64 || PPC64)
        depends on MEMORY_HOTPLUG && ARCH_ENABLE_MEMORY_HOTREMOVE
        depends on MIGRATION
 
@@ -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 c9f0a4339a7dafc2ba7295e49ad8fcdda8fa13de..5a7d58fb883bfa1c4917e48d251cd132c8d9baf9 100644 (file)
@@ -204,6 +204,8 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
        struct bio_vec *to, *from;
        unsigned i;
 
+       if (force)
+               goto bounce;
        bio_for_each_segment(from, *bio_orig, i)
                if (page_to_pfn(from->bv_page) > queue_bounce_pfn(q))
                        goto bounce;
index 05ccb4cc0bdb984dc2613461703587ec199804cd..b5326b141a251905a96cd5cd995063a29ca20f91 100644 (file)
@@ -677,6 +677,13 @@ static void isolate_freepages(struct zone *zone,
                                        pfn -= pageblock_nr_pages) {
                unsigned long isolated;
 
+               /*
+                * This can iterate a massively long zone without finding any
+                * suitable migration targets, so periodically check if we need
+                * to schedule.
+                */
+               cond_resched();
+
                if (!pfn_valid(pfn))
                        continue;
 
@@ -1131,6 +1138,9 @@ void compact_pgdat(pg_data_t *pgdat, int order)
                .sync = false,
        };
 
+       if (!order)
+               return;
+
        __compact_pgdat(pgdat, &cc);
 }
 
index 731a2c24532df32ca532184e7c714911a338dd9c..ae4846ff48494e9ac5e733a5d5339b61763a49f5 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);
index a92012a71702e7156baba919e636bcfcce8971f2..610e3df2768a6a5b2ec1e293da4c96dafbbe2d30 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;
-               }
-               count_vm_event(THP_FAULT_ALLOC);
-               if (unlikely(mem_cgroup_newpage_charge(page, mm, GFP_KERNEL))) {
-                       put_page(page);
-                       goto out;
+                       return VM_FAULT_FALLBACK;
                }
-               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
@@ -2707,6 +2697,7 @@ void __split_huge_page_pmd(struct vm_area_struct *vma, unsigned long address,
 
        mmun_start = haddr;
        mmun_end   = haddr + HPAGE_PMD_SIZE;
+again:
        mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
        spin_lock(&mm->page_table_lock);
        if (unlikely(!pmd_trans_huge(*pmd))) {
@@ -2729,7 +2720,14 @@ void __split_huge_page_pmd(struct vm_area_struct *vma, unsigned long address,
        split_huge_page(page);
 
        put_page(page);
-       BUG_ON(pmd_trans_huge(*pmd));
+
+       /*
+        * We don't always have down_write of mmap_sem here: a racing
+        * do_huge_pmd_wp_page() might have copied-on-write to another
+        * huge page before our split_huge_page() got the anon_vma lock.
+        */
+       if (unlikely(pmd_trans_huge(*pmd)))
+               goto again;
 }
 
 void split_huge_page_pmd_mm(struct mm_struct *mm, unsigned long address,
index b60f33080a28f0a078f8186e65ab8d878fced928..0b7656e804d126cf0fcfa04a8b427396af86deb1 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,21 @@ 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);
+       ClearPagePrivate(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);
@@ -664,8 +696,22 @@ static void prep_compound_gigantic_page(struct page *page, unsigned long order)
        /* we rely on prep_new_huge_page to set the destructor */
        set_compound_order(page, order);
        __SetPageHead(page);
+       __ClearPageReserved(page);
        for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) {
                __SetPageTail(p);
+               /*
+                * For gigantic hugepages allocated through bootmem at
+                * boot, it's safer to be consistent with the not-gigantic
+                * hugepages and clear the PG_reserved bit from all tail pages
+                * too.  Otherwse drivers using get_user_pages() to access tail
+                * pages may get the reference counting wrong if they see
+                * PG_reserved set on a tail page (despite the head page not
+                * having PG_reserved set).  Enforcing this consistency between
+                * head and tail pages allows drivers to optimize away a check
+                * on the head page when they need know if put_page() is needed
+                * after get_user_pages().
+                */
+               __ClearPageReserved(p);
                set_page_count(p, 0);
                p->first_page = page;
        }
@@ -715,7 +761,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 +818,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 +836,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 +879,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 +988,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 +1030,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 +1122,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 +1190,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 +1210,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 +1239,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 +1275,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 +1309,6 @@ int __weak alloc_bootmem_huge_page(struct hstate *h)
                        m = addr;
                        goto found;
                }
-               nr_nodes--;
        }
        return 0;
 
@@ -1252,9 +1344,9 @@ static void __init gather_bootmem_prealloc(void)
 #else
                page = virt_to_page(m);
 #endif
-               __ClearPageReserved(page);
                WARN_ON(page_count(page) != 1);
                prep_compound_huge_page(page, h->order);
+               WARN_ON(PageReserved(page));
                prep_new_huge_page(h, page, page_to_nid(page));
                /*
                 * If we had gigantic hugepages allocated at boot time, we need
@@ -1355,48 +1447,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 +1598,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 +1689,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 +2140,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 +2267,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 +2277,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 +2617,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 +2626,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 +2641,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 +2713,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 +2726,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 +2826,7 @@ retry:
                                        goto retry;
                                goto out;
                        }
+                       ClearPagePrivate(page);
 
                        spin_lock(&inode->i_lock);
                        inode->i_blocks += blocks_per_huge_page(h);
@@ -2813,8 +2873,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 +3493,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..4c84678371eb5b5905cc8c4386b512ec57e4f5e3 100644 (file)
@@ -20,8 +20,6 @@ static int hwpoison_inject(void *data, u64 val)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (!hwpoison_filter_enable)
-               goto inject;
        if (!pfn_valid(pfn))
                return -ENXIO;
 
@@ -33,6 +31,9 @@ static int hwpoison_inject(void *data, u64 val)
        if (!get_page_unless_zero(hpage))
                return 0;
 
+       if (!hwpoison_filter_enable)
+               goto inject;
+
        if (!PageLRU(p) && !PageHuge(p))
                shake_page(p, 0);
        /*
@@ -88,12 +89,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..539eeb96b323bf649f83783e0dddcb4f907e1d6e 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,35 @@ static long madvise_remove(struct vm_area_struct *vma,
  */
 static int madvise_hwpoison(int bhv, unsigned long start, unsigned long end)
 {
-       int ret = 0;
-
+       struct page *p;
        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);
+       for (; start < end; start += PAGE_SIZE <<
+                               compound_order(compound_head(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 +465,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..34d3ca9572d6baed85499d099a0050af3b9bdf66 100644 (file)
@@ -85,26 +85,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",
 };
 
@@ -280,6 +266,7 @@ struct mem_cgroup {
 
        bool            oom_lock;
        atomic_t        under_oom;
+       atomic_t        oom_wakeups;
 
        int     swappiness;
        /* OOM-Killer disable */
@@ -304,7 +291,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.
         */
@@ -879,6 +866,7 @@ static unsigned long mem_cgroup_read_events(struct mem_cgroup *memcg,
        unsigned long val = 0;
        int cpu;
 
+       get_online_cpus();
        for_each_online_cpu(cpu)
                val += per_cpu(memcg->stat->events[idx], cpu);
 #ifdef CONFIG_HOTPLUG_CPU
@@ -886,6 +874,7 @@ static unsigned long mem_cgroup_read_events(struct mem_cgroup *memcg,
        val += memcg->nocpu_base.events[idx];
        spin_unlock(&memcg->pcp_counter_lock);
 #endif
+       put_online_cpus();
        return val;
 }
 
@@ -2057,15 +2046,18 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
        return total;
 }
 
+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 +2071,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 +2121,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 +2150,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);
 }
@@ -2169,57 +2161,97 @@ static void memcg_oom_recover(struct mem_cgroup *memcg)
                memcg_wakeup_oom(memcg);
 }
 
-/*
- * try to call OOM killer. returns false if we should exit memory-reclaim loop.
+static void mem_cgroup_oom(struct mem_cgroup *memcg, gfp_t mask, int order)
+{
+       if (!current->memcg_oom.may_oom)
+               return;
+       /*
+        * We are in the middle of the charge context here, so we
+        * don't want to block when potentially sitting on a callstack
+        * that holds all kinds of filesystem and mm locks.
+        *
+        * Also, the caller may handle a failed allocation gracefully
+        * (like optional page cache readahead) and so an OOM killer
+        * invocation might not even be necessary.
+        *
+        * That's why we don't do anything here except remember the
+        * OOM context and then deal with it at the end of the page
+        * fault when the stack is unwound, the locks are released,
+        * and when we know whether the fault was overall successful.
+        */
+       css_get(&memcg->css);
+       current->memcg_oom.memcg = memcg;
+       current->memcg_oom.gfp_mask = mask;
+       current->memcg_oom.order = order;
+}
+
+/**
+ * mem_cgroup_oom_synchronize - complete memcg OOM handling
+ * @handle: actually kill/wait or just clean up the OOM state
+ *
+ * This has to be called at the end of a page fault if the memcg OOM
+ * handler was enabled.
+ *
+ * Memcg supports userspace OOM handling where 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 complete the OOM handling.
+ *
+ * Returns %true if an ongoing memcg OOM situation was detected and
+ * completed, %false otherwise.
  */
-static bool mem_cgroup_handle_oom(struct mem_cgroup *memcg, gfp_t mask,
-                                 int order)
+bool mem_cgroup_oom_synchronize(bool handle)
 {
+       struct mem_cgroup *memcg = current->memcg_oom.memcg;
        struct oom_wait_info owait;
-       bool locked, need_to_kill;
+       bool locked;
+
+       /* OOM is global, do not handle */
+       if (!memcg)
+               return false;
+
+       if (!handle)
+               goto cleanup;
 
        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);
 
-       /* 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.
-        */
        prepare_to_wait(&memcg_oom_waitq, &owait.wait, TASK_KILLABLE);
-       if (!locked || memcg->oom_kill_disable)
-               need_to_kill = false;
+       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) {
+       if (locked && !memcg->oom_kill_disable) {
+               mem_cgroup_unmark_under_oom(memcg);
                finish_wait(&memcg_oom_waitq, &owait.wait);
-               mem_cgroup_out_of_memory(memcg, mask, order);
+               mem_cgroup_out_of_memory(memcg, current->memcg_oom.gfp_mask,
+                                        current->memcg_oom.order);
        } else {
                schedule();
+               mem_cgroup_unmark_under_oom(memcg);
                finish_wait(&memcg_oom_waitq, &owait.wait);
        }
-       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);
-
-       if (test_thread_flag(TIF_MEMDIE) || fatal_signal_pending(current))
-               return false;
-       /* Give chance to dying process */
-       schedule_timeout_uninterruptible(1);
+       if (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);
+       }
+cleanup:
+       current->memcg_oom.memcg = NULL;
+       css_put(&memcg->css);
        return true;
 }
 
@@ -2288,7 +2320,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 +2329,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 +2475,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 +2557,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 +2618,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;
 }
 
 /*
@@ -2645,6 +2665,9 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
                     || fatal_signal_pending(current)))
                goto bypass;
 
+       if (unlikely(task_in_memcg_oom(current)))
+               goto bypass;
+
        /*
         * We always charge the cgroup the mm_struct belongs to.
         * The mm_struct's mem_cgroup changes on task migration if the
@@ -2704,7 +2727,7 @@ again:
        }
 
        do {
-               bool oom_check;
+               bool invoke_oom = oom && !nr_oom_retries;
 
                /* If killed, bypass charge */
                if (fatal_signal_pending(current)) {
@@ -2712,14 +2735,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 +2749,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);
 
@@ -2753,6 +2766,8 @@ done:
        return 0;
 nomem:
        *ptr = NULL;
+       if (gfp_mask & __GFP_NOFAIL)
+               return 0;
        return -ENOMEM;
 bypass:
        *ptr = root_mem_cgroup;
@@ -2882,7 +2897,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);
 
@@ -3121,7 +3136,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 +3179,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 +3641,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 +3765,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 +3824,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 +4687,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 +4708,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)) {
@@ -4987,18 +5020,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 +5163,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 +5173,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 +5615,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)
index d84c5e5331bb5199632f46fda6d3ca3fef9dbaf4..bf3351b5115e54915a3d7eaa718d10a9771b2c5f 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);
 }
@@ -1112,8 +1114,10 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
                         * shake_page could have turned it free.
                         */
                        if (is_free_buddy_page(p)) {
-                               action_result(pfn, "free buddy, 2nd try",
-                                               DELAYED);
+                               if (flags & MF_COUNT_INCREASED)
+                                       action_result(pfn, "free buddy", DELAYED);
+                               else
+                                       action_result(pfn, "free buddy, 2nd try", DELAYED);
                                return 0;
                        }
                        action_result(pfn, "non LRU", IGNORED);
@@ -1204,6 +1208,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 +1346,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 (!PageHuge(page) && 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 +1370,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 +1392,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 +1433,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 +1488,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 +1504,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 +1613,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..1311f26497e6a0f776682ed8a7e23b8620a5b9ad 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.
@@ -861,6 +837,8 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                                         */
                                        make_migration_entry_read(&entry);
                                        pte = swp_entry_to_pte(entry);
+                                       if (pte_swp_soft_dirty(*src_pte))
+                                               pte = pte_swp_mksoft_dirty(pte);
                                        set_pte_at(src_mm, addr, src_pte, pte);
                                }
                        }
@@ -1505,7 +1483,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 +1495,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 +3697,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 +3756,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 +3776,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 +3847,43 @@ 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_oom_enable();
+
+       ret = __handle_mm_fault(mm, vma, address, flags);
+
+       if (flags & FAULT_FLAG_USER) {
+               mem_cgroup_oom_disable();
+                /*
+                 * The task may have entered a memcg OOM situation but
+                 * if the allocation error was handled gracefully (no
+                 * VM_FAULT_OOM), there is no need to kill anything.
+                 * Just clean up the OOM state peacefully.
+                 */
+                if (task_in_memcg_oom(current) && !(ret & VM_FAULT_OOM))
+                        mem_cgroup_oom_synchronize(false);
+       }
+
+       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..7a7325ee1d089696a8073a84d2f748f326124805 100644 (file)
@@ -100,10 +100,14 @@ 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));
-               if (unlikely(balloon_page_movable(page)))
+               if (unlikely(isolated_balloon_page(page)))
                        balloon_page_putback(page);
                else
                        putback_lru_page(page);
@@ -157,6 +161,8 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
 
        get_page(new);
        pte = pte_mkold(mk_pte(new, vma->vm_page_prot));
+       if (pte_swp_soft_dirty(*ptep))
+               pte = pte_mksoft_dirty(pte);
        if (is_write_migration_entry(entry))
                pte = pte_mkwrite(pte);
 #ifdef CONFIG_HUGETLB_PAGE
@@ -307,7 +313,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 +951,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 +991,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 +1043,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 +1080,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 +1104,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 +1168,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 +1195,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 +1473,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..d480cd6fc475854259bdd51021d5125dbdfbe479 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,195 @@ 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, as it was pinned under the same
+        * mmap_sem write op.
+        */
+       pte = get_locked_pte(vma->vm_mm, start, &ptl);
+       /* Make sure we do not cross the page table boundary */
+       end = pgd_addr_end(start, end);
+       end = pud_addr_end(start, end);
+       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 +439,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 +454,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();
        }
 }
@@ -506,6 +740,7 @@ static int do_mlockall(int flags)
 
                /* Ignore errors */
                mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags);
+               cond_resched();
        }
 out:
        return 0;
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 94722a4d6b438311de1d1690d81a0d598a907339..a3af058f68e4d9f434337d0dcd6127d5d8c6d039 100644 (file)
@@ -94,13 +94,16 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                        swp_entry_t entry = pte_to_swp_entry(oldpte);
 
                        if (is_write_migration_entry(entry)) {
+                               pte_t newpte;
                                /*
                                 * A protection check is difficult so
                                 * just be safe and disable write
                                 */
                                make_migration_entry_read(&entry);
-                               set_pte_at(mm, addr, pte,
-                                       swp_entry_to_pte(entry));
+                               newpte = swp_entry_to_pte(entry);
+                               if (pte_swp_soft_dirty(oldpte))
+                                       newpte = pte_swp_mksoft_dirty(newpte);
+                               set_pte_at(mm, addr, pte, newpte);
                        }
                        pages++;
                }
index 98e75f2ac7bc3ad01f1287e9697948e6212610d4..6738c47f1f7280edc5f3fe610b2658195a0a77e0 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(true))
+               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..63807583d8e89f1c96f8b05bcf5fe422ed200c26 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));
@@ -1104,11 +1210,11 @@ static unsigned long dirty_poll_interval(unsigned long dirty,
        return 1;
 }
 
-static long bdi_max_pause(struct backing_dev_info *bdi,
-                         unsigned long bdi_dirty)
+static unsigned long bdi_max_pause(struct backing_dev_info *bdi,
+                                  unsigned long bdi_dirty)
 {
-       long bw = bdi->avg_write_bandwidth;
-       long t;
+       unsigned long bw = bdi->avg_write_bandwidth;
+       unsigned long t;
 
        /*
         * Limit pause time for small memory systems. If sleeping for too long
@@ -1120,7 +1226,7 @@ static long bdi_max_pause(struct backing_dev_info *bdi,
        t = bdi_dirty / (1 + bw / roundup_pow_of_two(1 + HZ / 8));
        t++;
 
-       return min_t(long, t, MAX_PAUSE);
+       return min_t(unsigned long, t, MAX_PAUSE);
 }
 
 static long bdi_min_pause(struct backing_dev_info *bdi,
@@ -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..dd886fac451ab6ab7d6a3132fd2587c10538f300 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.
@@ -6274,10 +6366,6 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
                list_del(&page->lru);
                rmv_page_order(page);
                zone->free_area[order].nr_free--;
-#ifdef CONFIG_HIGHMEM
-               if (PageHighMem(page))
-                       totalhigh_pages -= 1 << order;
-#endif
                for (i = 0; i < (1 << order); i++)
                        SetPageReserved((page+i));
                pfn += (1 << order);
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..e2e98af703ea9fdcbab4bcd034bc82a1482c9ca6 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"
 
@@ -55,6 +56,7 @@ static int kmem_cache_sanity_check(struct mem_cgroup *memcg, const char *name,
                        continue;
                }
 
+#if !defined(CONFIG_SLUB) || !defined(CONFIG_SLUB_DEBUG_ON)
                /*
                 * For simplicity, we won't check this in the list of memcg
                 * caches. We have control over memcg naming, and if there
@@ -68,6 +70,7 @@ static int kmem_cache_sanity_check(struct mem_cgroup *memcg, const char *name,
                        s = NULL;
                        return -EINVAL;
                }
+#endif
        }
 
        WARN_ON(strchr(name, ' '));     /* It confuses parsers */
@@ -373,7 +376,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 +498,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..de7c904e52e507079f5bae7a2b7854a9d7cf80b0 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;
@@ -1583,6 +1824,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        struct filename *pathname;
        int i, type, prev;
        int err;
+       unsigned int old_block_size;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -1651,6 +1893,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);
@@ -1671,10 +1915,13 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        }
 
        swap_file = p->swap_file;
+       old_block_size = p->old_block_size;
        p->swap_file = NULL;
        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 +1929,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);
@@ -1690,7 +1940,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        inode = mapping->host;
        if (S_ISBLK(inode->i_mode)) {
                struct block_device *bdev = I_BDEV(inode);
-               set_blocksize(bdev, p->old_block_size);
+               set_blocksize(bdev, old_block_size);
                blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
        } else {
                mutex_lock(&inode->i_mutex);
@@ -1926,9 +2176,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 +2193,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 +2218,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 +2236,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 +2250,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 +2274,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 +2301,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 +2360,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 +2375,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 +2436,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 +2476,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 +2511,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 +2532,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 +2545,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 +2615,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 +2660,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..eea668d9cff6c578ada0cf6c02eca5e22de5598d 100644 (file)
@@ -48,6 +48,7 @@
 #include <asm/div64.h>
 
 #include <linux/swapops.h>
+#include <linux/balloon_compaction.h>
 
 #include "internal.h"
 
@@ -146,6 +147,25 @@ static bool global_reclaim(struct scan_control *sc)
 }
 #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 +175,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);
 
@@ -174,18 +211,106 @@ void unregister_shrinker(struct shrinker *shrinker)
        down_write(&shrinker_rwsem);
        list_del(&shrinker->list);
        up_write(&shrinker_rwsem);
+       kfree(shrinker->nr_deferred);
 }
 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 +330,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();
-               }
+                       freed += shrink_slab_node(shrinkctl, shrinker,
+                                nr_pages_scanned, lru_pages);
 
-               /*
-                * 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);
-
-               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 +600,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 +615,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 +642,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 +653,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 */
@@ -1060,7 +1115,8 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
        LIST_HEAD(clean_pages);
 
        list_for_each_entry_safe(page, next, page_list, lru) {
-               if (page_is_file_cache(page) && !PageDirty(page)) {
+               if (page_is_file_cache(page) && !PageDirty(page) &&
+                   !isolated_balloon_page(page)) {
                        ClearPageActive(page);
                        list_move(&page->lru, &clean_pages);
                }
@@ -1789,7 +1845,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;
@@ -2244,8 +2300,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)) {
                                /*
@@ -2283,11 +2339,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 +2352,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 +2405,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 +2767,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 +2828,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 +2870,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 +2888,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);
@@ -2901,8 +2954,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,8 +3033,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;
 
                        sc.nr_scanned = 0;
@@ -3237,7 +3290,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 +3318,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 +3563,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 +3614,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..d93510c6aa2da860d779570cbf0a4c7cee278ad5 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,32 +790,24 @@ 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);
        }
        tree->rbroot = RB_ROOT;
        spin_unlock(&tree->lock);
+
+       zbud_destroy_pool(tree->pool);
+       kfree(tree);
+       zswap_trees[type] = NULL;
 }
 
 static struct zbud_ops zswap_zbud_ops = {
index 1eb05d80b07bea736e85a389be0d98c8bfcb3d9c..3ed616215870cf73b4d8a516d52e5da04d9472e5 100644 (file)
 static unsigned int mrp_join_time __read_mostly = 200;
 module_param(mrp_join_time, uint, 0644);
 MODULE_PARM_DESC(mrp_join_time, "Join time in ms (default 200ms)");
+
+static unsigned int mrp_periodic_time __read_mostly = 1000;
+module_param(mrp_periodic_time, uint, 0644);
+MODULE_PARM_DESC(mrp_periodic_time, "Periodic time in ms (default 1s)");
+
 MODULE_LICENSE("GPL");
 
 static const u8
@@ -595,6 +600,24 @@ static void mrp_join_timer(unsigned long data)
        mrp_join_timer_arm(app);
 }
 
+static void mrp_periodic_timer_arm(struct mrp_applicant *app)
+{
+       mod_timer(&app->periodic_timer,
+                 jiffies + msecs_to_jiffies(mrp_periodic_time));
+}
+
+static void mrp_periodic_timer(unsigned long data)
+{
+       struct mrp_applicant *app = (struct mrp_applicant *)data;
+
+       spin_lock(&app->lock);
+       mrp_mad_event(app, MRP_EVENT_PERIODIC);
+       mrp_pdu_queue(app);
+       spin_unlock(&app->lock);
+
+       mrp_periodic_timer_arm(app);
+}
+
 static int mrp_pdu_parse_end_mark(struct sk_buff *skb, int *offset)
 {
        __be16 endmark;
@@ -845,6 +868,9 @@ int mrp_init_applicant(struct net_device *dev, struct mrp_application *appl)
        rcu_assign_pointer(dev->mrp_port->applicants[appl->type], app);
        setup_timer(&app->join_timer, mrp_join_timer, (unsigned long)app);
        mrp_join_timer_arm(app);
+       setup_timer(&app->periodic_timer, mrp_periodic_timer,
+                   (unsigned long)app);
+       mrp_periodic_timer_arm(app);
        return 0;
 
 err3:
@@ -870,6 +896,7 @@ void mrp_uninit_applicant(struct net_device *dev, struct mrp_application *appl)
         * all pending messages before the applicant is gone.
         */
        del_timer_sync(&app->join_timer);
+       del_timer_sync(&app->periodic_timer);
 
        spin_lock_bh(&app->lock);
        mrp_mad_event(app, MRP_EVENT_TX);
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 634debab4d54582f04c69a4664b00c7541696a93..fb7356fcfe51e03664d7aed6458eafd3015634e5 100644 (file)
@@ -1146,7 +1146,11 @@ int hci_dev_open(__u16 dev)
                goto done;
        }
 
-       if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) {
+       /* Check for rfkill but allow the HCI setup stage to proceed
+        * (which in itself doesn't cause any RF activity).
+        */
+       if (test_bit(HCI_RFKILLED, &hdev->dev_flags) &&
+           !test_bit(HCI_SETUP, &hdev->dev_flags)) {
                ret = -ERFKILL;
                goto done;
        }
@@ -1566,10 +1570,13 @@ static int hci_rfkill_set_block(void *data, bool blocked)
 
        BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);
 
-       if (!blocked)
-               return 0;
-
-       hci_dev_do_close(hdev);
+       if (blocked) {
+               set_bit(HCI_RFKILLED, &hdev->dev_flags);
+               if (!test_bit(HCI_SETUP, &hdev->dev_flags))
+                       hci_dev_do_close(hdev);
+       } else {
+               clear_bit(HCI_RFKILLED, &hdev->dev_flags);
+       }
 
        return 0;
 }
@@ -1591,9 +1598,13 @@ static void hci_power_on(struct work_struct *work)
                return;
        }
 
-       if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
+       if (test_bit(HCI_RFKILLED, &hdev->dev_flags)) {
+               clear_bit(HCI_AUTO_OFF, &hdev->dev_flags);
+               hci_dev_do_close(hdev);
+       } else if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
                queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
                                   HCI_AUTO_OFF_TIMEOUT);
+       }
 
        if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
                mgmt_index_added(hdev);
@@ -2209,6 +2220,9 @@ int hci_register_dev(struct hci_dev *hdev)
                }
        }
 
+       if (hdev->rfkill && rfkill_blocked(hdev->rfkill))
+               set_bit(HCI_RFKILLED, &hdev->dev_flags);
+
        set_bit(HCI_SETUP, &hdev->dev_flags);
 
        if (hdev->dev_type != HCI_AMP)
index 94aab73f89d4c9e447d2b65f12f8ec71ee1a66e6..8db3e89fae354aebb67c6ea7172a3e2e1926b66d 100644 (file)
@@ -3557,7 +3557,11 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
        cp.handle = cpu_to_le16(conn->handle);
 
        if (ltk->authenticated)
-               conn->sec_level = BT_SECURITY_HIGH;
+               conn->pending_sec_level = BT_SECURITY_HIGH;
+       else
+               conn->pending_sec_level = BT_SECURITY_MEDIUM;
+
+       conn->enc_key_size = ltk->enc_size;
 
        hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
 
index b3bb7bca8e606439edbd9f9838bb8021200bb28c..63fa11109a1c391725d5efec2075c1524d9f1a1a 100644 (file)
@@ -3755,6 +3755,13 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
 
        sk = chan->sk;
 
+       /* For certain devices (ex: HID mouse), support for authentication,
+        * pairing and bonding is optional. For such devices, inorder to avoid
+        * the ACL alive for too long after L2CAP disconnection, reset the ACL
+        * disc_timeout back to HCI_DISCONN_TIMEOUT during L2CAP connect.
+        */
+       conn->hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
+
        bacpy(&bt_sk(sk)->src, conn->src);
        bacpy(&bt_sk(sk)->dst, conn->dst);
        chan->psm  = psm;
index 6d126faf145fe5107fbd0dfd9b810671c34e1e66..84fcf9fff3ea52e4235b7e478deb487fb075b53c 100644 (file)
@@ -569,7 +569,6 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
 static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
 {
        struct rfcomm_dev *dev = dlc->owner;
-       struct tty_struct *tty;
        if (!dev)
                return;
 
@@ -581,38 +580,8 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
                            DPM_ORDER_DEV_AFTER_PARENT);
 
                wake_up_interruptible(&dev->port.open_wait);
-       } else if (dlc->state == BT_CLOSED) {
-               tty = tty_port_tty_get(&dev->port);
-               if (!tty) {
-                       if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
-                               /* Drop DLC lock here to avoid deadlock
-                                * 1. rfcomm_dev_get will take rfcomm_dev_lock
-                                *    but in rfcomm_dev_add there's lock order:
-                                *    rfcomm_dev_lock -> dlc lock
-                                * 2. tty_port_put will deadlock if it's
-                                *    the last reference
-                                *
-                                * FIXME: when we release the lock anything
-                                * could happen to dev, even its destruction
-                                */
-                               rfcomm_dlc_unlock(dlc);
-                               if (rfcomm_dev_get(dev->id) == NULL) {
-                                       rfcomm_dlc_lock(dlc);
-                                       return;
-                               }
-
-                               if (!test_and_set_bit(RFCOMM_TTY_RELEASED,
-                                                     &dev->flags))
-                                       tty_port_put(&dev->port);
-
-                               tty_port_put(&dev->port);
-                               rfcomm_dlc_lock(dlc);
-                       }
-               } else {
-                       tty_hangup(tty);
-                       tty_kref_put(tty);
-               }
-       }
+       } else if (dlc->state == BT_CLOSED)
+               tty_port_tty_hangup(&dev->port, false);
 }
 
 static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
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 5c713f2239cc6245d230d2e35e243bbee7339761..65f829cfd928b3bda157b0848e13edfa5b118bae 100644 (file)
@@ -5247,10 +5247,12 @@ static int dev_new_index(struct net *net)
 
 /* Delayed registration/unregisteration */
 static LIST_HEAD(net_todo_list);
+static DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq);
 
 static void net_set_todo(struct net_device *dev)
 {
        list_add_tail(&dev->todo_list, &net_todo_list);
+       dev_net(dev)->dev_unreg_count++;
 }
 
 static void rollback_registered_many(struct list_head *head)
@@ -5918,6 +5920,12 @@ void netdev_run_todo(void)
                if (dev->destructor)
                        dev->destructor(dev);
 
+               /* Report a network device has been unregistered */
+               rtnl_lock();
+               dev_net(dev)->dev_unreg_count--;
+               __rtnl_unlock();
+               wake_up(&netdev_unregistering_wq);
+
                /* Free network device */
                kobject_put(&dev->dev.kobj);
        }
@@ -6603,6 +6611,34 @@ static void __net_exit default_device_exit(struct net *net)
        rtnl_unlock();
 }
 
+static void __net_exit rtnl_lock_unregistering(struct list_head *net_list)
+{
+       /* Return with the rtnl_lock held when there are no network
+        * devices unregistering in any network namespace in net_list.
+        */
+       struct net *net;
+       bool unregistering;
+       DEFINE_WAIT(wait);
+
+       for (;;) {
+               prepare_to_wait(&netdev_unregistering_wq, &wait,
+                               TASK_UNINTERRUPTIBLE);
+               unregistering = false;
+               rtnl_lock();
+               list_for_each_entry(net, net_list, exit_list) {
+                       if (net->dev_unreg_count > 0) {
+                               unregistering = true;
+                               break;
+                       }
+               }
+               if (!unregistering)
+                       break;
+               __rtnl_unlock();
+               schedule();
+       }
+       finish_wait(&netdev_unregistering_wq, &wait);
+}
+
 static void __net_exit default_device_exit_batch(struct list_head *net_list)
 {
        /* At exit all network devices most be removed from a network
@@ -6614,7 +6650,18 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list)
        struct net *net;
        LIST_HEAD(dev_kill_list);
 
-       rtnl_lock();
+       /* To prevent network device cleanup code from dereferencing
+        * loopback devices or network devices that have been freed
+        * wait here for all pending unregistrations to complete,
+        * before unregistring the loopback device and allowing the
+        * network namespace be freed.
+        *
+        * The netdev todo list containing all network devices
+        * unregistrations that happen in default_device_exit_batch
+        * will run in the rtnl_unlock() at the end of
+        * default_device_exit_batch.
+        */
+       rtnl_lock_unregistering(net_list);
        list_for_each_entry(net, net_list, exit_list) {
                for_each_netdev_reverse(net, dev) {
                        if (dev->rtnl_link_ops)
index 0ff42f029ace683610115f5251554dc3e87b9210..8d7d0dd72db211e23b5bcffd16f7600841841598 100644 (file)
@@ -154,8 +154,8 @@ ipv6:
        if (poff >= 0) {
                __be32 *ports, _ports;
 
-               nhoff += poff;
-               ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports);
+               ports = skb_header_pointer(skb, nhoff + poff,
+                                          sizeof(_ports), &_ports);
                if (ports)
                        flow->ports = *ports;
        }
@@ -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 3f40ea9de8149d9dc56f09b884160ff43a53a3d0..d954b56b4e47976b3b003c41cb7b39758d5d044d 100644 (file)
@@ -1196,6 +1196,13 @@ static void remove_queue_kobjects(struct net_device *net)
 #endif
 }
 
+static bool net_current_may_mount(void)
+{
+       struct net *net = current->nsproxy->net_ns;
+
+       return ns_capable(net->user_ns, CAP_SYS_ADMIN);
+}
+
 static void *net_grab_current_ns(void)
 {
        struct net *ns = current->nsproxy->net_ns;
@@ -1218,6 +1225,7 @@ static const void *net_netlink_ns(struct sock *sk)
 
 struct kobj_ns_type_operations net_ns_type_operations = {
        .type = KOBJ_NS_TYPE_NET,
+       .current_may_mount = net_current_may_mount,
        .grab_current_ns = net_grab_current_ns,
        .netlink_ns = net_netlink_ns,
        .initial_ns = net_initial_ns,
index f976520367542a5fdfc9e609e16a5a696dd767ad..81d3a9a084536541867afe9350602c0c73253006 100644 (file)
@@ -651,7 +651,7 @@ static int netns_install(struct nsproxy *nsproxy, void *ns)
        struct net *net = ns;
 
        if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) ||
-           !nsown_capable(CAP_SYS_ADMIN))
+           !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
                return -EPERM;
 
        put_net(nsproxy->net_ns);
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 b4da80b1cc07d28eafec50a6185d6d2a2ece61af..b442e7e25e601b19a8237d1a90efbaa1d572fc19 100644 (file)
@@ -56,9 +56,9 @@ static __inline__ int scm_check_creds(struct ucred *creds)
        if ((creds->pid == task_tgid_vnr(current) ||
             ns_capable(task_active_pid_ns(current)->user_ns, CAP_SYS_ADMIN)) &&
            ((uid_eq(uid, cred->uid)   || uid_eq(uid, cred->euid) ||
-             uid_eq(uid, cred->suid)) || nsown_capable(CAP_SETUID)) &&
+             uid_eq(uid, cred->suid)) || ns_capable(cred->user_ns, CAP_SETUID)) &&
            ((gid_eq(gid, cred->gid)   || gid_eq(gid, cred->egid) ||
-             gid_eq(gid, cred->sgid)) || nsown_capable(CAP_SETGID))) {
+             gid_eq(gid, cred->sgid)) || ns_capable(cred->user_ns, CAP_SETGID))) {
               return 0;
        }
        return -EPERM;
index 6a2f13cee86a0c3f34f69832d4b6d93592fd5327..3f1ec1586ae174d9bea18de2bcada31c3c88a5bb 100644 (file)
 
 #include <net/secure_seq.h>
 
-static u32 net_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
+#define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4)
 
-void net_secret_init(void)
+static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned;
+
+static void net_secret_init(void)
 {
-       get_random_bytes(net_secret, sizeof(net_secret));
+       u32 tmp;
+       int i;
+
+       if (likely(net_secret[0]))
+               return;
+
+       for (i = NET_SECRET_SIZE; i > 0;) {
+               do {
+                       get_random_bytes(&tmp, sizeof(tmp));
+               } while (!tmp);
+               cmpxchg(&net_secret[--i], 0, tmp);
+       }
 }
 
 #ifdef CONFIG_INET
@@ -42,6 +55,7 @@ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
        u32 hash[MD5_DIGEST_WORDS];
        u32 i;
 
+       net_secret_init();
        memcpy(hash, saddr, 16);
        for (i = 0; i < 4; i++)
                secret[i] = net_secret[i] + (__force u32)daddr[i];
@@ -63,6 +77,7 @@ u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
        u32 hash[MD5_DIGEST_WORDS];
        u32 i;
 
+       net_secret_init();
        memcpy(hash, saddr, 16);
        for (i = 0; i < 4; i++)
                secret[i] = net_secret[i] + (__force u32) daddr[i];
@@ -82,6 +97,7 @@ __u32 secure_ip_id(__be32 daddr)
 {
        u32 hash[MD5_DIGEST_WORDS];
 
+       net_secret_init();
        hash[0] = (__force __u32) daddr;
        hash[1] = net_secret[13];
        hash[2] = net_secret[14];
@@ -96,6 +112,7 @@ __u32 secure_ipv6_id(const __be32 daddr[4])
 {
        __u32 hash[4];
 
+       net_secret_init();
        memcpy(hash, daddr, 16);
        md5_transform(hash, net_secret);
 
@@ -107,6 +124,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
 {
        u32 hash[MD5_DIGEST_WORDS];
 
+       net_secret_init();
        hash[0] = (__force u32)saddr;
        hash[1] = (__force u32)daddr;
        hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
@@ -121,6 +139,7 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
 {
        u32 hash[MD5_DIGEST_WORDS];
 
+       net_secret_init();
        hash[0] = (__force u32)saddr;
        hash[1] = (__force u32)daddr;
        hash[2] = (__force u32)dport ^ net_secret[14];
@@ -140,6 +159,7 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
        u32 hash[MD5_DIGEST_WORDS];
        u64 seq;
 
+       net_secret_init();
        hash[0] = (__force u32)saddr;
        hash[1] = (__force u32)daddr;
        hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
@@ -164,6 +184,7 @@ u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
        u64 seq;
        u32 i;
 
+       net_secret_init();
        memcpy(hash, saddr, 16);
        for (i = 0; i < 4; i++)
                secret[i] = net_secret[i] + daddr[i];
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 7a1874b7b8fd4431b6cc7d383ae5e96923dbdda3..cfeb85cff4f02abc28570b267ba6e64784595fab 100644 (file)
@@ -263,10 +263,8 @@ void build_ehash_secret(void)
                get_random_bytes(&rnd, sizeof(rnd));
        } while (rnd == 0);
 
-       if (cmpxchg(&inet_ehash_secret, 0, rnd) == 0) {
+       if (cmpxchg(&inet_ehash_secret, 0, rnd) == 0)
                get_random_bytes(&ipv6_hash_secret, sizeof(ipv6_hash_secret));
-               net_secret_init();
-       }
 }
 EXPORT_SYMBOL(build_ehash_secret);
 
index d6c0e64ec97f2147124e84d4b634f263bac9eb95..7defdc9ba16744fd263c539c37f125fc31422c87 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;
@@ -736,7 +736,7 @@ static void igmp_gq_timer_expire(unsigned long data)
 
        in_dev->mr_gq_running = 0;
        igmpv3_send_report(in_dev, NULL);
-       __in_dev_put(in_dev);
+       in_dev_put(in_dev);
 }
 
 static void igmp_ifc_timer_expire(unsigned long data)
@@ -749,7 +749,7 @@ static void igmp_ifc_timer_expire(unsigned long data)
                igmp_ifc_start_timer(in_dev,
                                     unsolicited_report_interval(in_dev));
        }
-       __in_dev_put(in_dev);
+       in_dev_put(in_dev);
 }
 
 static void igmp_ifc_event(struct in_device *in_dev)
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 ac9fabe0300f613e87bbe4d70e9c861fbc95889e..63a6d6d6b87581d3ac3bda52cab5833f3cb169ab 100644 (file)
@@ -623,6 +623,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                        tunnel->err_count = 0;
        }
 
+       tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
        ttl = tnl_params->ttl;
        if (ttl == 0) {
                if (skb->protocol == htons(ETH_P_IP))
@@ -641,18 +642,17 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
 
        max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr)
                        + rt->dst.header_len;
-       if (max_headroom > dev->needed_headroom) {
+       if (max_headroom > dev->needed_headroom)
                dev->needed_headroom = max_headroom;
-               if (skb_cow_head(skb, dev->needed_headroom)) {
-                       dev->stats.tx_dropped++;
-                       dev_kfree_skb(skb);
-                       return;
-               }
+
+       if (skb_cow_head(skb, dev->needed_headroom)) {
+               dev->stats.tx_dropped++;
+               dev_kfree_skb(skb);
+               return;
        }
 
        err = iptunnel_xmit(rt, skb, fl4.saddr, fl4.daddr, protocol,
-                           ip_tunnel_ecn_encap(tos, inner_iph, skb), ttl, df,
-                           !net_eq(tunnel->net, dev_net(dev)));
+                           tos, ttl, df, !net_eq(tunnel->net, dev_net(dev)));
        iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
 
        return;
@@ -853,8 +853,10 @@ int ip_tunnel_init_net(struct net *net, int ip_tnl_net_id,
        /* FB netdevice is special: we have one, and only one per netns.
         * Allowing to move it to another netns is clearly unsafe.
         */
-       if (!IS_ERR(itn->fb_tunnel_dev))
+       if (!IS_ERR(itn->fb_tunnel_dev)) {
                itn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
+               ip_tunnel_add(itn, netdev_priv(itn->fb_tunnel_dev));
+       }
        rtnl_unlock();
 
        return PTR_RET(itn->fb_tunnel_dev);
@@ -884,8 +886,6 @@ static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head,
                        if (!net_eq(dev_net(t->dev), net))
                                unregister_netdevice_queue(t->dev, head);
        }
-       if (itn->fb_tunnel_dev)
-               unregister_netdevice_queue(itn->fb_tunnel_dev, head);
 }
 
 void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops)
index d6c856b17fd4ff22c0034af676a648730dffce82..c31e3ad98ef28e91eff2679d6976d4c20c055410 100644 (file)
@@ -61,7 +61,7 @@ int iptunnel_xmit(struct rtable *rt, struct sk_buff *skb,
        memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
 
        /* Push down and install the IP header. */
-       __skb_push(skb, sizeof(struct iphdr));
+       skb_push(skb, sizeof(struct iphdr));
        skb_reset_network_header(skb);
 
        iph = ip_hdr(skb);
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 67e17dcda65e64f27b9ca5b244561ab2d7fc594f..b6346bf2fde3bc16f0655e9c9f7c6ade5ffeae8a 100644 (file)
@@ -267,7 +267,8 @@ synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par)
        if (th == NULL)
                return NF_DROP;
 
-       synproxy_parse_options(skb, par->thoff, th, &opts);
+       if (!synproxy_parse_options(skb, par->thoff, th, &opts))
+               return NF_DROP;
 
        if (th->syn && !(th->ack || th->fin || th->rst)) {
                /* Initial SYN from client */
@@ -350,7 +351,8 @@ static unsigned int ipv4_synproxy_hook(unsigned int hooknum,
 
                /* fall through */
        case TCP_CONNTRACK_SYN_SENT:
-               synproxy_parse_options(skb, thoff, th, &opts);
+               if (!synproxy_parse_options(skb, thoff, th, &opts))
+                       return NF_DROP;
 
                if (!th->syn && th->ack &&
                    CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
@@ -373,7 +375,9 @@ static unsigned int ipv4_synproxy_hook(unsigned int hooknum,
                if (!th->syn || !th->ack)
                        break;
 
-               synproxy_parse_options(skb, thoff, th, &opts);
+               if (!synproxy_parse_options(skb, thoff, th, &opts))
+                       return NF_DROP;
+
                if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
                        synproxy->tsoff = opts.tsval - synproxy->its;
 
index a86c7ae71881b1e65e998888c92749fe63fcf3c1..193db03540ad7c8dabd2f88be81fb5fe78eb8eab 100644 (file)
@@ -218,8 +218,10 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
 
        if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
                ipv4_sk_update_pmtu(skb, sk, info);
-       else if (type == ICMP_REDIRECT)
+       else if (type == ICMP_REDIRECT) {
                ipv4_sk_redirect(skb, sk);
+               return;
+       }
 
        /* Report error on raw socket, if:
           1. User requested ip_recverr.
@@ -387,7 +389,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 1969e16d936d9b5cd37c01309df27ef31c9b2437..25a89eaa669de9240036abc04f1385eb168f995e 100644 (file)
@@ -3162,16 +3162,14 @@ static inline bool tcp_may_raise_cwnd(const struct sock *sk, const int flag)
 
        /* If reordering is high then always grow cwnd whenever data is
         * delivered regardless of its ordering. Otherwise stay conservative
-        * and only grow cwnd on in-order delivery in Open state, and retain
-        * cwnd in Disordered state (RFC5681). A stretched ACK with
+        * and only grow cwnd on in-order delivery (RFC5681). A stretched ACK w/
         * new SACK or ECE mark may first advance cwnd here and later reduce
         * cwnd in tcp_fastretrans_alert() based on more states.
         */
        if (tcp_sk(sk)->reordering > sysctl_tcp_reordering)
                return flag & FLAG_FORWARD_PROGRESS;
 
-       return inet_csk(sk)->icsk_ca_state == TCP_CA_Open &&
-              flag & FLAG_DATA_ACKED;
+       return flag & FLAG_DATA_ACKED;
 }
 
 /* Check that window update is acceptable.
@@ -4141,6 +4139,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
                if (!tcp_try_coalesce(sk, skb1, skb, &fragstolen)) {
                        __skb_queue_after(&tp->out_of_order_queue, skb1, skb);
                } else {
+                       tcp_grow_window(sk, skb);
                        kfree_skb_partial(skb, fragstolen);
                        skb = NULL;
                }
@@ -4216,8 +4215,10 @@ add_sack:
        if (tcp_is_sack(tp))
                tcp_sack_new_ofo_skb(sk, seq, end_seq);
 end:
-       if (skb)
+       if (skb) {
+               tcp_grow_window(sk, skb);
                skb_set_owner_r(skb, sk);
+       }
 }
 
 static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen,
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 7c83cb8bf1378022ba3a68c56403ef40801cd3ae..e6bb8256e59f3738280a022f250f6fefd621cb38 100644 (file)
@@ -895,8 +895,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
 
        skb_orphan(skb);
        skb->sk = sk;
-       skb->destructor = (sysctl_tcp_limit_output_bytes > 0) ?
-                         tcp_wfree : sock_wfree;
+       skb->destructor = tcp_wfree;
        atomic_add(skb->truesize, &sk->sk_wmem_alloc);
 
        /* Build TCP header and checksum it. */
@@ -1840,7 +1839,6 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
        while ((skb = tcp_send_head(sk))) {
                unsigned int limit;
 
-
                tso_segs = tcp_init_tso_segs(sk, skb, mss_now);
                BUG_ON(!tso_segs);
 
@@ -1869,13 +1867,20 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                                break;
                }
 
-               /* TSQ : sk_wmem_alloc accounts skb truesize,
-                * including skb overhead. But thats OK.
+               /* TCP Small Queues :
+                * Control number of packets in qdisc/devices to two packets / or ~1 ms.
+                * This allows for :
+                *  - better RTT estimation and ACK scheduling
+                *  - faster recovery
+                *  - high rates
                 */
-               if (atomic_read(&sk->sk_wmem_alloc) >= sysctl_tcp_limit_output_bytes) {
+               limit = max(skb->truesize, sk->sk_pacing_rate >> 10);
+
+               if (atomic_read(&sk->sk_wmem_alloc) > limit) {
                        set_bit(TSQ_THROTTLED, &tp->tsq_flags);
                        break;
                }
+
                limit = mss_now;
                if (tso_segs > 1 && !tcp_urg_mode(tp))
                        limit = tcp_mss_split_point(sk, skb, mss_now,
index 74d2c95db57f3768d62ee450ed6bab64ca09b26d..0ca44df51ee94a2875427e5c9d3b1c77434f5f40 100644 (file)
@@ -658,7 +658,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
                break;
        case ICMP_REDIRECT:
                ipv4_sk_redirect(skb, sk);
-               break;
+               goto out;
        }
 
        /*
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 d6ff12617f36f9eabbf7c9744b3b8121a567c1bf..cd3fb301da38a970cd48302386428a8923f21c91 100644 (file)
@@ -1499,6 +1499,33 @@ static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
        return false;
 }
 
+/* Compares an address/prefix_len with addresses on device @dev.
+ * If one is found it returns true.
+ */
+bool ipv6_chk_custom_prefix(const struct in6_addr *addr,
+       const unsigned int prefix_len, struct net_device *dev)
+{
+       struct inet6_dev *idev;
+       struct inet6_ifaddr *ifa;
+       bool ret = false;
+
+       rcu_read_lock();
+       idev = __in6_dev_get(dev);
+       if (idev) {
+               read_lock_bh(&idev->lock);
+               list_for_each_entry(ifa, &idev->addr_list, if_list) {
+                       ret = ipv6_prefix_equal(addr, &ifa->addr, prefix_len);
+                       if (ret)
+                               break;
+               }
+               read_unlock_bh(&idev->lock);
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+EXPORT_SYMBOL(ipv6_chk_custom_prefix);
+
 int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev)
 {
        struct inet6_dev *idev;
@@ -2193,43 +2220,21 @@ ok:
                        else
                                stored_lft = 0;
                        if (!update_lft && !create && stored_lft) {
-                               if (valid_lft > MIN_VALID_LIFETIME ||
-                                   valid_lft > stored_lft)
-                                       update_lft = 1;
-                               else if (stored_lft <= MIN_VALID_LIFETIME) {
-                                       /* valid_lft <= stored_lft is always true */
-                                       /*
-                                        * RFC 4862 Section 5.5.3e:
-                                        * "Note that the preferred lifetime of
-                                        *  the corresponding address is always
-                                        *  reset to the Preferred Lifetime in
-                                        *  the received Prefix Information
-                                        *  option, regardless of whether the
-                                        *  valid lifetime is also reset or
-                                        *  ignored."
-                                        *
-                                        *  So if the preferred lifetime in
-                                        *  this advertisement is different
-                                        *  than what we have stored, but the
-                                        *  valid lifetime is invalid, just
-                                        *  reset prefered_lft.
-                                        *
-                                        *  We must set the valid lifetime
-                                        *  to the stored lifetime since we'll
-                                        *  be updating the timestamp below,
-                                        *  else we'll set it back to the
-                                        *  minimum.
-                                        */
-                                       if (prefered_lft != ifp->prefered_lft) {
-                                               valid_lft = stored_lft;
-                                               update_lft = 1;
-                                       }
-                               } else {
-                                       valid_lft = MIN_VALID_LIFETIME;
-                                       if (valid_lft < prefered_lft)
-                                               prefered_lft = valid_lft;
-                                       update_lft = 1;
-                               }
+                               const u32 minimum_lft = min(
+                                       stored_lft, (u32)MIN_VALID_LIFETIME);
+                               valid_lft = max(valid_lft, minimum_lft);
+
+                               /* RFC4862 Section 5.5.3e:
+                                * "Note that the preferred lifetime of the
+                                *  corresponding address is always reset to
+                                *  the Preferred Lifetime in the received
+                                *  Prefix Information option, regardless of
+                                *  whether the valid lifetime is also reset or
+                                *  ignored."
+                                *
+                                * So we should always update prefered_lft here.
+                                */
+                               update_lft = 1;
                        }
 
                        if (update_lft) {
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 6b26e9feafb98eb8d269f553cbf8339a3341526b..7bb5446b9d73c16a7f4096f2705ce60f997c7c2a 100644 (file)
@@ -618,7 +618,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
        struct ip6_tnl *tunnel = netdev_priv(dev);
        struct net_device *tdev;    /* Device to other host */
        struct ipv6hdr  *ipv6h;     /* Our new IP header */
-       unsigned int max_headroom /* The extra header space needed */
+       unsigned int max_headroom = 0; /* The extra header space needed */
        int    gre_hlen;
        struct ipv6_tel_txoption opt;
        int    mtu;
@@ -693,7 +693,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
 
        skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev)));
 
-       max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + dst->header_len;
+       max_headroom += LL_RESERVED_SPACE(tdev) + gre_hlen + dst->header_len;
 
        if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
            (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
index 3a692d5291636571266c6e26293bc7054228f4e3..a54c45ce4a48f0d3a65f6c54ac77bb73a6a41280 100644 (file)
@@ -1015,6 +1015,8 @@ static inline int ip6_ufo_append_data(struct sock *sk,
         * udp datagram
         */
        if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) {
+               struct frag_hdr fhdr;
+
                skb = sock_alloc_send_skb(sk,
                        hh_len + fragheaderlen + transhdrlen + 20,
                        (flags & MSG_DONTWAIT), &err);
@@ -1036,12 +1038,6 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                skb->protocol = htons(ETH_P_IPV6);
                skb->ip_summed = CHECKSUM_PARTIAL;
                skb->csum = 0;
-       }
-
-       err = skb_append_datato_frags(sk,skb, getfrag, from,
-                                     (length - transhdrlen));
-       if (!err) {
-               struct frag_hdr fhdr;
 
                /* Specify the length of each IPv6 datagram fragment.
                 * It has to be a multiple of 8.
@@ -1052,15 +1048,10 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                ipv6_select_ident(&fhdr, rt);
                skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
                __skb_queue_tail(&sk->sk_write_queue, skb);
-
-               return 0;
        }
-       /* There is not enough support do UPD LSO,
-        * so follow normal path
-        */
-       kfree_skb(skb);
 
-       return err;
+       return skb_append_datato_frags(sk, skb, getfrag, from,
+                                      (length - transhdrlen));
 }
 
 static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src,
@@ -1227,27 +1218,27 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
         * --yoshfuji
         */
 
-       cork->length += length;
-       if (length > mtu) {
-               int proto = sk->sk_protocol;
-               if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){
-                       ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen);
-                       return -EMSGSIZE;
-               }
-
-               if (proto == IPPROTO_UDP &&
-                   (rt->dst.dev->features & NETIF_F_UFO)) {
+       if ((length > mtu) && dontfrag && (sk->sk_protocol == IPPROTO_UDP ||
+                                          sk->sk_protocol == IPPROTO_RAW)) {
+               ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen);
+               return -EMSGSIZE;
+       }
 
-                       err = ip6_ufo_append_data(sk, getfrag, from, length,
-                                                 hh_len, fragheaderlen,
-                                                 transhdrlen, mtu, flags, rt);
-                       if (err)
-                               goto error;
-                       return 0;
-               }
+       skb = skb_peek_tail(&sk->sk_write_queue);
+       cork->length += length;
+       if (((length > mtu) ||
+            (skb && skb_is_gso(skb))) &&
+           (sk->sk_protocol == IPPROTO_UDP) &&
+           (rt->dst.dev->features & NETIF_F_UFO)) {
+               err = ip6_ufo_append_data(sk, getfrag, from, length,
+                                         hh_len, fragheaderlen,
+                                         transhdrlen, mtu, flags, rt);
+               if (err)
+                       goto error;
+               return 0;
        }
 
-       if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL)
+       if (!skb)
                goto alloc_new_skb;
 
        while (length > 0) {
index 61355f7f4da5b4bb7bcc3c12030e09abe9fa9691..a791552e042212d866b2cd96c35e2f0b5d289ab5 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) ||
@@ -1731,8 +1731,6 @@ static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n)
                }
        }
 
-       t = rtnl_dereference(ip6n->tnls_wc[0]);
-       unregister_netdevice_queue(t->dev, &list);
        unregister_netdevice_many(&list);
 }
 
@@ -1752,6 +1750,7 @@ static int __net_init ip6_tnl_init_net(struct net *net)
        if (!ip6n->fb_tnl_dev)
                goto err_alloc_dev;
        dev_net_set(ip6n->fb_tnl_dev, net);
+       ip6n->fb_tnl_dev->rtnl_link_ops = &ip6_link_ops;
        /* FB netdevice is special: we have one, and only one per netns.
         * Allowing to move it to another netns is clearly unsafe.
         */
index 096cd67b737c4b4eba2d42470d7a58e2e229153c..d18f9f903db62333983d3fad0e1ccb9298762c98 100644 (file)
@@ -2034,7 +2034,7 @@ static void mld_dad_timer_expire(unsigned long data)
                if (idev->mc_dad_count)
                        mld_dad_start_timer(idev, idev->mc_maxdelay);
        }
-       __in6_dev_put(idev);
+       in6_dev_put(idev);
 }
 
 static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
@@ -2379,7 +2379,7 @@ static void mld_gq_timer_expire(unsigned long data)
 
        idev->mc_gq_running = 0;
        mld_send_report(idev, NULL);
-       __in6_dev_put(idev);
+       in6_dev_put(idev);
 }
 
 static void mld_ifc_timer_expire(unsigned long data)
@@ -2392,7 +2392,7 @@ static void mld_ifc_timer_expire(unsigned long data)
                if (idev->mc_ifc_count)
                        mld_ifc_start_timer(idev, idev->mc_maxdelay);
        }
-       __in6_dev_put(idev);
+       in6_dev_put(idev);
 }
 
 static void mld_ifc_event(struct inet6_dev *idev)
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 19cfea8dbcaa0547c85e40f4217105ef46c7b683..2748b042da72eceb4002cf4183a781282c5e84d4 100644 (file)
@@ -282,7 +282,8 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
        if (th == NULL)
                return NF_DROP;
 
-       synproxy_parse_options(skb, par->thoff, th, &opts);
+       if (!synproxy_parse_options(skb, par->thoff, th, &opts))
+               return NF_DROP;
 
        if (th->syn && !(th->ack || th->fin || th->rst)) {
                /* Initial SYN from client */
@@ -372,7 +373,8 @@ static unsigned int ipv6_synproxy_hook(unsigned int hooknum,
 
                /* fall through */
        case TCP_CONNTRACK_SYN_SENT:
-               synproxy_parse_options(skb, thoff, th, &opts);
+               if (!synproxy_parse_options(skb, thoff, th, &opts))
+                       return NF_DROP;
 
                if (!th->syn && th->ack &&
                    CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
@@ -395,7 +397,9 @@ static unsigned int ipv6_synproxy_hook(unsigned int hooknum,
                if (!th->syn || !th->ack)
                        break;
 
-               synproxy_parse_options(skb, thoff, th, &opts);
+               if (!synproxy_parse_options(skb, thoff, th, &opts))
+                       return NF_DROP;
+
                if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
                        synproxy->tsoff = opts.tsval - synproxy->its;
 
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 58916bbb17284ed441611d0210c9514141ff9bf4..a4ed2416399ed52622b9c60460d411b9507e6d85 100644 (file)
@@ -335,8 +335,10 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb,
                ip6_sk_update_pmtu(skb, sk, info);
                harderr = (np->pmtudisc == IPV6_PMTUDISC_DO);
        }
-       if (type == NDISC_REDIRECT)
+       if (type == NDISC_REDIRECT) {
                ip6_sk_redirect(skb, sk);
+               return;
+       }
        if (np->recverr) {
                u8 *payload = skb->data;
                if (!inet->hdrincl)
index 7ee5cb96db348ab5c75946e77d3068c3c447ba17..19269453a8eaca1d34eefa648e401ccea7d829ac 100644 (file)
@@ -566,6 +566,70 @@ static inline bool is_spoofed_6rd(struct ip_tunnel *tunnel, const __be32 v4addr,
        return false;
 }
 
+/* Checks if an address matches an address on the tunnel interface.
+ * Used to detect the NAT of proto 41 packets and let them pass spoofing test.
+ * Long story:
+ * This function is called after we considered the packet as spoofed
+ * in is_spoofed_6rd.
+ * We may have a router that is doing NAT for proto 41 packets
+ * for an internal station. Destination a.a.a.a/PREFIX:bbbb:bbbb
+ * will be translated to n.n.n.n/PREFIX:bbbb:bbbb. And is_spoofed_6rd
+ * function will return true, dropping the packet.
+ * But, we can still check if is spoofed against the IP
+ * addresses associated with the interface.
+ */
+static bool only_dnatted(const struct ip_tunnel *tunnel,
+       const struct in6_addr *v6dst)
+{
+       int prefix_len;
+
+#ifdef CONFIG_IPV6_SIT_6RD
+       prefix_len = tunnel->ip6rd.prefixlen + 32
+               - tunnel->ip6rd.relay_prefixlen;
+#else
+       prefix_len = 48;
+#endif
+       return ipv6_chk_custom_prefix(v6dst, prefix_len, tunnel->dev);
+}
+
+/* Returns true if a packet is spoofed */
+static bool packet_is_spoofed(struct sk_buff *skb,
+                             const struct iphdr *iph,
+                             struct ip_tunnel *tunnel)
+{
+       const struct ipv6hdr *ipv6h;
+
+       if (tunnel->dev->priv_flags & IFF_ISATAP) {
+               if (!isatap_chksrc(skb, iph, tunnel))
+                       return true;
+
+               return false;
+       }
+
+       if (tunnel->dev->flags & IFF_POINTOPOINT)
+               return false;
+
+       ipv6h = ipv6_hdr(skb);
+
+       if (unlikely(is_spoofed_6rd(tunnel, iph->saddr, &ipv6h->saddr))) {
+               net_warn_ratelimited("Src spoofed %pI4/%pI6c -> %pI4/%pI6c\n",
+                                    &iph->saddr, &ipv6h->saddr,
+                                    &iph->daddr, &ipv6h->daddr);
+               return true;
+       }
+
+       if (likely(!is_spoofed_6rd(tunnel, iph->daddr, &ipv6h->daddr)))
+               return false;
+
+       if (only_dnatted(tunnel, &ipv6h->daddr))
+               return false;
+
+       net_warn_ratelimited("Dst spoofed %pI4/%pI6c -> %pI4/%pI6c\n",
+                            &iph->saddr, &ipv6h->saddr,
+                            &iph->daddr, &ipv6h->daddr);
+       return true;
+}
+
 static int ipip6_rcv(struct sk_buff *skb)
 {
        const struct iphdr *iph = ip_hdr(skb);
@@ -586,19 +650,9 @@ static int ipip6_rcv(struct sk_buff *skb)
                IPCB(skb)->flags = 0;
                skb->protocol = htons(ETH_P_IPV6);
 
-               if (tunnel->dev->priv_flags & IFF_ISATAP) {
-                       if (!isatap_chksrc(skb, iph, tunnel)) {
-                               tunnel->dev->stats.rx_errors++;
-                               goto out;
-                       }
-               } else if (!(tunnel->dev->flags&IFF_POINTOPOINT)) {
-                       if (is_spoofed_6rd(tunnel, iph->saddr,
-                                          &ipv6_hdr(skb)->saddr) ||
-                           is_spoofed_6rd(tunnel, iph->daddr,
-                                          &ipv6_hdr(skb)->daddr)) {
-                               tunnel->dev->stats.rx_errors++;
-                               goto out;
-                       }
+               if (packet_is_spoofed(skb, iph, tunnel)) {
+                       tunnel->dev->stats.rx_errors++;
+                       goto out;
                }
 
                __skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
@@ -748,7 +802,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
                        neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr);
 
                if (neigh == NULL) {
-                       net_dbg_ratelimited("sit: nexthop == NULL\n");
+                       net_dbg_ratelimited("nexthop == NULL\n");
                        goto tx_error;
                }
 
@@ -777,7 +831,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
                        neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr);
 
                if (neigh == NULL) {
-                       net_dbg_ratelimited("sit: nexthop == NULL\n");
+                       net_dbg_ratelimited("nexthop == NULL\n");
                        goto tx_error;
                }
 
@@ -1612,6 +1666,7 @@ static int __net_init sit_init_net(struct net *net)
                goto err_alloc_dev;
        }
        dev_net_set(sitn->fb_tunnel_dev, net);
+       sitn->fb_tunnel_dev->rtnl_link_ops = &sit_link_ops;
        /* FB netdevice is special: we have one, and only one per netns.
         * Allowing to move it to another netns is clearly unsafe.
         */
@@ -1646,7 +1701,6 @@ static void __net_exit sit_exit_net(struct net *net)
 
        rtnl_lock();
        sit_destroy_tunnels(sitn, &list);
-       unregister_netdevice_queue(sitn->fb_tunnel_dev, &list);
        unregister_netdevice_many(&list);
        rtnl_unlock();
 }
index f4058150262b111d316a423e1c9ddc7ee8bb29a0..72b7eaaf3ca0e3e6b7cad3edea8aa69e71cbe147 100644 (file)
@@ -525,8 +525,10 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
        if (type == ICMPV6_PKT_TOOBIG)
                ip6_sk_update_pmtu(skb, sk, info);
-       if (type == NDISC_REDIRECT)
+       if (type == NDISC_REDIRECT) {
                ip6_sk_redirect(skb, sk);
+               goto out;
+       }
 
        np = inet6_sk(sk);
 
index 54563ad8aeb1f02bbedd18959c8cf9cd77479942..355cc3b6fa4d3e4040bf9fb1578fc43c6c4f7b52 100644 (file)
@@ -154,6 +154,7 @@ static void lapb_t1timer_expiry(unsigned long param)
                        } else {
                                lapb->n2count++;
                                lapb_requeue_frames(lapb);
+                               lapb_kick(lapb);
                        }
                        break;
 
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 4f69e83ff836b0ec415342772055a58a52c25fc4..74fd00c272100d5271533689abf074c5f9e8c454 100644 (file)
@@ -116,6 +116,7 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
 
        if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
                struct ip_vs_cpu_stats *s;
+               struct ip_vs_service *svc;
 
                s = this_cpu_ptr(dest->stats.cpustats);
                s->ustats.inpkts++;
@@ -123,11 +124,14 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
                s->ustats.inbytes += skb->len;
                u64_stats_update_end(&s->syncp);
 
-               s = this_cpu_ptr(dest->svc->stats.cpustats);
+               rcu_read_lock();
+               svc = rcu_dereference(dest->svc);
+               s = this_cpu_ptr(svc->stats.cpustats);
                s->ustats.inpkts++;
                u64_stats_update_begin(&s->syncp);
                s->ustats.inbytes += skb->len;
                u64_stats_update_end(&s->syncp);
+               rcu_read_unlock();
 
                s = this_cpu_ptr(ipvs->tot_stats.cpustats);
                s->ustats.inpkts++;
@@ -146,6 +150,7 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
 
        if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
                struct ip_vs_cpu_stats *s;
+               struct ip_vs_service *svc;
 
                s = this_cpu_ptr(dest->stats.cpustats);
                s->ustats.outpkts++;
@@ -153,11 +158,14 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
                s->ustats.outbytes += skb->len;
                u64_stats_update_end(&s->syncp);
 
-               s = this_cpu_ptr(dest->svc->stats.cpustats);
+               rcu_read_lock();
+               svc = rcu_dereference(dest->svc);
+               s = this_cpu_ptr(svc->stats.cpustats);
                s->ustats.outpkts++;
                u64_stats_update_begin(&s->syncp);
                s->ustats.outbytes += skb->len;
                u64_stats_update_end(&s->syncp);
+               rcu_read_unlock();
 
                s = this_cpu_ptr(ipvs->tot_stats.cpustats);
                s->ustats.outpkts++;
index c8148e48738657d63810a1dade924267dc032d01..a3df9bddc4f76251a8722792d8e9f15478546ac1 100644 (file)
@@ -460,7 +460,7 @@ static inline void
 __ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc)
 {
        atomic_inc(&svc->refcnt);
-       dest->svc = svc;
+       rcu_assign_pointer(dest->svc, svc);
 }
 
 static void ip_vs_service_free(struct ip_vs_service *svc)
@@ -470,18 +470,25 @@ static void ip_vs_service_free(struct ip_vs_service *svc)
        kfree(svc);
 }
 
-static void
-__ip_vs_unbind_svc(struct ip_vs_dest *dest)
+static void ip_vs_service_rcu_free(struct rcu_head *head)
 {
-       struct ip_vs_service *svc = dest->svc;
+       struct ip_vs_service *svc;
+
+       svc = container_of(head, struct ip_vs_service, rcu_head);
+       ip_vs_service_free(svc);
+}
 
-       dest->svc = NULL;
+static void __ip_vs_svc_put(struct ip_vs_service *svc, bool do_delay)
+{
        if (atomic_dec_and_test(&svc->refcnt)) {
                IP_VS_DBG_BUF(3, "Removing service %u/%s:%u\n",
                              svc->fwmark,
                              IP_VS_DBG_ADDR(svc->af, &svc->addr),
                              ntohs(svc->port));
-               ip_vs_service_free(svc);
+               if (do_delay)
+                       call_rcu(&svc->rcu_head, ip_vs_service_rcu_free);
+               else
+                       ip_vs_service_free(svc);
        }
 }
 
@@ -667,11 +674,6 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
                              IP_VS_DBG_ADDR(svc->af, &dest->addr),
                              ntohs(dest->port),
                              atomic_read(&dest->refcnt));
-               /* We can not reuse dest while in grace period
-                * because conns still can use dest->svc
-                */
-               if (test_bit(IP_VS_DEST_STATE_REMOVING, &dest->state))
-                       continue;
                if (dest->af == svc->af &&
                    ip_vs_addr_equal(svc->af, &dest->addr, daddr) &&
                    dest->port == dport &&
@@ -697,8 +699,10 @@ out:
 
 static void ip_vs_dest_free(struct ip_vs_dest *dest)
 {
+       struct ip_vs_service *svc = rcu_dereference_protected(dest->svc, 1);
+
        __ip_vs_dst_cache_reset(dest);
-       __ip_vs_unbind_svc(dest);
+       __ip_vs_svc_put(svc, false);
        free_percpu(dest->stats.cpustats);
        kfree(dest);
 }
@@ -771,6 +775,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
                    struct ip_vs_dest_user_kern *udest, int add)
 {
        struct netns_ipvs *ipvs = net_ipvs(svc->net);
+       struct ip_vs_service *old_svc;
        struct ip_vs_scheduler *sched;
        int conn_flags;
 
@@ -792,13 +797,14 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
        atomic_set(&dest->conn_flags, conn_flags);
 
        /* bind the service */
-       if (!dest->svc) {
+       old_svc = rcu_dereference_protected(dest->svc, 1);
+       if (!old_svc) {
                __ip_vs_bind_svc(dest, svc);
        } else {
-               if (dest->svc != svc) {
-                       __ip_vs_unbind_svc(dest);
+               if (old_svc != svc) {
                        ip_vs_zero_stats(&dest->stats);
                        __ip_vs_bind_svc(dest, svc);
+                       __ip_vs_svc_put(old_svc, true);
                }
        }
 
@@ -998,16 +1004,6 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
        return 0;
 }
 
-static void ip_vs_dest_wait_readers(struct rcu_head *head)
-{
-       struct ip_vs_dest *dest = container_of(head, struct ip_vs_dest,
-                                              rcu_head);
-
-       /* End of grace period after unlinking */
-       clear_bit(IP_VS_DEST_STATE_REMOVING, &dest->state);
-}
-
-
 /*
  *     Delete a destination (must be already unlinked from the service)
  */
@@ -1023,20 +1019,16 @@ static void __ip_vs_del_dest(struct net *net, struct ip_vs_dest *dest,
         */
        ip_vs_rs_unhash(dest);
 
-       if (!cleanup) {
-               set_bit(IP_VS_DEST_STATE_REMOVING, &dest->state);
-               call_rcu(&dest->rcu_head, ip_vs_dest_wait_readers);
-       }
-
        spin_lock_bh(&ipvs->dest_trash_lock);
        IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, dest->refcnt=%d\n",
                      IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
                      atomic_read(&dest->refcnt));
        if (list_empty(&ipvs->dest_trash) && !cleanup)
                mod_timer(&ipvs->dest_trash_timer,
-                         jiffies + IP_VS_DEST_TRASH_PERIOD);
+                         jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
        /* dest lives in trash without reference */
        list_add(&dest->t_list, &ipvs->dest_trash);
+       dest->idle_start = 0;
        spin_unlock_bh(&ipvs->dest_trash_lock);
        ip_vs_dest_put(dest);
 }
@@ -1108,24 +1100,30 @@ static void ip_vs_dest_trash_expire(unsigned long data)
        struct net *net = (struct net *) data;
        struct netns_ipvs *ipvs = net_ipvs(net);
        struct ip_vs_dest *dest, *next;
+       unsigned long now = jiffies;
 
        spin_lock(&ipvs->dest_trash_lock);
        list_for_each_entry_safe(dest, next, &ipvs->dest_trash, t_list) {
-               /* Skip if dest is in grace period */
-               if (test_bit(IP_VS_DEST_STATE_REMOVING, &dest->state))
-                       continue;
                if (atomic_read(&dest->refcnt) > 0)
                        continue;
+               if (dest->idle_start) {
+                       if (time_before(now, dest->idle_start +
+                                            IP_VS_DEST_TRASH_PERIOD))
+                               continue;
+               } else {
+                       dest->idle_start = max(1UL, now);
+                       continue;
+               }
                IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u from trash\n",
                              dest->vfwmark,
-                             IP_VS_DBG_ADDR(dest->svc->af, &dest->addr),
+                             IP_VS_DBG_ADDR(dest->af, &dest->addr),
                              ntohs(dest->port));
                list_del(&dest->t_list);
                ip_vs_dest_free(dest);
        }
        if (!list_empty(&ipvs->dest_trash))
                mod_timer(&ipvs->dest_trash_timer,
-                         jiffies + IP_VS_DEST_TRASH_PERIOD);
+                         jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
        spin_unlock(&ipvs->dest_trash_lock);
 }
 
@@ -1320,14 +1318,6 @@ out:
        return ret;
 }
 
-static void ip_vs_service_rcu_free(struct rcu_head *head)
-{
-       struct ip_vs_service *svc;
-
-       svc = container_of(head, struct ip_vs_service, rcu_head);
-       ip_vs_service_free(svc);
-}
-
 /*
  *     Delete a service from the service list
  *     - The service must be unlinked, unlocked and not referenced!
@@ -1376,13 +1366,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup)
        /*
         *    Free the service if nobody refers to it
         */
-       if (atomic_dec_and_test(&svc->refcnt)) {
-               IP_VS_DBG_BUF(3, "Removing service %u/%s:%u\n",
-                             svc->fwmark,
-                             IP_VS_DBG_ADDR(svc->af, &svc->addr),
-                             ntohs(svc->port));
-               call_rcu(&svc->rcu_head, ip_vs_service_rcu_free);
-       }
+       __ip_vs_svc_put(svc, true);
 
        /* decrease the module use count */
        ip_vs_use_count_dec();
index 6bee6d0c73a52e93e1413162b4db971340fa3312..1425e9a924c4f64429637bc49cbde204b0bb1921 100644 (file)
@@ -59,12 +59,13 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
                                 struct ip_vs_cpu_stats __percpu *stats)
 {
        int i;
+       bool add = false;
 
        for_each_possible_cpu(i) {
                struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
                unsigned int start;
                __u64 inbytes, outbytes;
-               if (i) {
+               if (add) {
                        sum->conns += s->ustats.conns;
                        sum->inpkts += s->ustats.inpkts;
                        sum->outpkts += s->ustats.outpkts;
@@ -76,6 +77,7 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
                        sum->inbytes += inbytes;
                        sum->outbytes += outbytes;
                } else {
+                       add = true;
                        sum->conns = s->ustats.conns;
                        sum->inpkts = s->ustats.inpkts;
                        sum->outpkts = s->ustats.outpkts;
index 1383b0eadc0e777d5ff6dbce2a2ded451a3ae296..eff13c94498e068173c66b6a481a6264d038ffea 100644 (file)
@@ -93,7 +93,7 @@ struct ip_vs_lblc_entry {
        struct hlist_node       list;
        int                     af;             /* address family */
        union nf_inet_addr      addr;           /* destination IP address */
-       struct ip_vs_dest __rcu *dest;          /* real server (cache) */
+       struct ip_vs_dest       *dest;          /* real server (cache) */
        unsigned long           lastuse;        /* last used time */
        struct rcu_head         rcu_head;
 };
@@ -130,20 +130,21 @@ static struct ctl_table vs_vars_table[] = {
 };
 #endif
 
-static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en)
+static void ip_vs_lblc_rcu_free(struct rcu_head *head)
 {
-       struct ip_vs_dest *dest;
+       struct ip_vs_lblc_entry *en = container_of(head,
+                                                  struct ip_vs_lblc_entry,
+                                                  rcu_head);
 
-       hlist_del_rcu(&en->list);
-       /*
-        * We don't kfree dest because it is referred either by its service
-        * or the trash dest list.
-        */
-       dest = rcu_dereference_protected(en->dest, 1);
-       ip_vs_dest_put(dest);
-       kfree_rcu(en, rcu_head);
+       ip_vs_dest_put(en->dest);
+       kfree(en);
 }
 
+static inline void ip_vs_lblc_del(struct ip_vs_lblc_entry *en)
+{
+       hlist_del_rcu(&en->list);
+       call_rcu(&en->rcu_head, ip_vs_lblc_rcu_free);
+}
 
 /*
  *     Returns hash value for IPVS LBLC entry
@@ -203,30 +204,23 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,
        struct ip_vs_lblc_entry *en;
 
        en = ip_vs_lblc_get(dest->af, tbl, daddr);
-       if (!en) {
-               en = kmalloc(sizeof(*en), GFP_ATOMIC);
-               if (!en)
-                       return NULL;
-
-               en->af = dest->af;
-               ip_vs_addr_copy(dest->af, &en->addr, daddr);
-               en->lastuse = jiffies;
+       if (en) {
+               if (en->dest == dest)
+                       return en;
+               ip_vs_lblc_del(en);
+       }
+       en = kmalloc(sizeof(*en), GFP_ATOMIC);
+       if (!en)
+               return NULL;
 
-               ip_vs_dest_hold(dest);
-               RCU_INIT_POINTER(en->dest, dest);
+       en->af = dest->af;
+       ip_vs_addr_copy(dest->af, &en->addr, daddr);
+       en->lastuse = jiffies;
 
-               ip_vs_lblc_hash(tbl, en);
-       } else {
-               struct ip_vs_dest *old_dest;
+       ip_vs_dest_hold(dest);
+       en->dest = dest;
 
-               old_dest = rcu_dereference_protected(en->dest, 1);
-               if (old_dest != dest) {
-                       ip_vs_dest_put(old_dest);
-                       ip_vs_dest_hold(dest);
-                       /* No ordering constraints for refcnt */
-                       RCU_INIT_POINTER(en->dest, dest);
-               }
-       }
+       ip_vs_lblc_hash(tbl, en);
 
        return en;
 }
@@ -246,7 +240,7 @@ static void ip_vs_lblc_flush(struct ip_vs_service *svc)
        tbl->dead = 1;
        for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
                hlist_for_each_entry_safe(en, next, &tbl->bucket[i], list) {
-                       ip_vs_lblc_free(en);
+                       ip_vs_lblc_del(en);
                        atomic_dec(&tbl->entries);
                }
        }
@@ -281,7 +275,7 @@ static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
                                        sysctl_lblc_expiration(svc)))
                                continue;
 
-                       ip_vs_lblc_free(en);
+                       ip_vs_lblc_del(en);
                        atomic_dec(&tbl->entries);
                }
                spin_unlock(&svc->sched_lock);
@@ -335,7 +329,7 @@ static void ip_vs_lblc_check_expire(unsigned long data)
                        if (time_before(now, en->lastuse + ENTRY_TIMEOUT))
                                continue;
 
-                       ip_vs_lblc_free(en);
+                       ip_vs_lblc_del(en);
                        atomic_dec(&tbl->entries);
                        goal--;
                }
@@ -443,8 +437,8 @@ __ip_vs_lblc_schedule(struct ip_vs_service *svc)
                        continue;
 
                doh = ip_vs_dest_conn_overhead(dest);
-               if (loh * atomic_read(&dest->weight) >
-                   doh * atomic_read(&least->weight)) {
+               if ((__s64)loh * atomic_read(&dest->weight) >
+                   (__s64)doh * atomic_read(&least->weight)) {
                        least = dest;
                        loh = doh;
                }
@@ -511,7 +505,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                 * free up entries from the trash at any time.
                 */
 
-               dest = rcu_dereference(en->dest);
+               dest = en->dest;
                if ((dest->flags & IP_VS_DEST_F_AVAILABLE) &&
                    atomic_read(&dest->weight) > 0 && !is_overloaded(dest, svc))
                        goto out;
@@ -631,7 +625,7 @@ static void __exit ip_vs_lblc_cleanup(void)
 {
        unregister_ip_vs_scheduler(&ip_vs_lblc_scheduler);
        unregister_pernet_subsys(&ip_vs_lblc_ops);
-       synchronize_rcu();
+       rcu_barrier();
 }
 
 
index 5199448697f64fcf0da0e35dbc38903477a92861..0b8550089a2e580e7feba0723117f1c849048a39 100644 (file)
@@ -89,7 +89,7 @@
  */
 struct ip_vs_dest_set_elem {
        struct list_head        list;          /* list link */
-       struct ip_vs_dest __rcu *dest;         /* destination server */
+       struct ip_vs_dest       *dest;          /* destination server */
        struct rcu_head         rcu_head;
 };
 
@@ -107,11 +107,7 @@ static void ip_vs_dest_set_insert(struct ip_vs_dest_set *set,
 
        if (check) {
                list_for_each_entry(e, &set->list, list) {
-                       struct ip_vs_dest *d;
-
-                       d = rcu_dereference_protected(e->dest, 1);
-                       if (d == dest)
-                               /* already existed */
+                       if (e->dest == dest)
                                return;
                }
        }
@@ -121,7 +117,7 @@ static void ip_vs_dest_set_insert(struct ip_vs_dest_set *set,
                return;
 
        ip_vs_dest_hold(dest);
-       RCU_INIT_POINTER(e->dest, dest);
+       e->dest = dest;
 
        list_add_rcu(&e->list, &set->list);
        atomic_inc(&set->size);
@@ -129,22 +125,27 @@ static void ip_vs_dest_set_insert(struct ip_vs_dest_set *set,
        set->lastmod = jiffies;
 }
 
+static void ip_vs_lblcr_elem_rcu_free(struct rcu_head *head)
+{
+       struct ip_vs_dest_set_elem *e;
+
+       e = container_of(head, struct ip_vs_dest_set_elem, rcu_head);
+       ip_vs_dest_put(e->dest);
+       kfree(e);
+}
+
 static void
 ip_vs_dest_set_erase(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
 {
        struct ip_vs_dest_set_elem *e;
 
        list_for_each_entry(e, &set->list, list) {
-               struct ip_vs_dest *d;
-
-               d = rcu_dereference_protected(e->dest, 1);
-               if (d == dest) {
+               if (e->dest == dest) {
                        /* HIT */
                        atomic_dec(&set->size);
                        set->lastmod = jiffies;
-                       ip_vs_dest_put(dest);
                        list_del_rcu(&e->list);
-                       kfree_rcu(e, rcu_head);
+                       call_rcu(&e->rcu_head, ip_vs_lblcr_elem_rcu_free);
                        break;
                }
        }
@@ -155,16 +156,8 @@ static void ip_vs_dest_set_eraseall(struct ip_vs_dest_set *set)
        struct ip_vs_dest_set_elem *e, *ep;
 
        list_for_each_entry_safe(e, ep, &set->list, list) {
-               struct ip_vs_dest *d;
-
-               d = rcu_dereference_protected(e->dest, 1);
-               /*
-                * We don't kfree dest because it is referred either
-                * by its service or by the trash dest list.
-                */
-               ip_vs_dest_put(d);
                list_del_rcu(&e->list);
-               kfree_rcu(e, rcu_head);
+               call_rcu(&e->rcu_head, ip_vs_lblcr_elem_rcu_free);
        }
 }
 
@@ -175,12 +168,9 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
        struct ip_vs_dest *dest, *least;
        int loh, doh;
 
-       if (set == NULL)
-               return NULL;
-
        /* select the first destination server, whose weight > 0 */
        list_for_each_entry_rcu(e, &set->list, list) {
-               least = rcu_dereference(e->dest);
+               least = e->dest;
                if (least->flags & IP_VS_DEST_F_OVERLOAD)
                        continue;
 
@@ -195,13 +185,13 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
        /* find the destination with the weighted least load */
   nextstage:
        list_for_each_entry_continue_rcu(e, &set->list, list) {
-               dest = rcu_dereference(e->dest);
+               dest = e->dest;
                if (dest->flags & IP_VS_DEST_F_OVERLOAD)
                        continue;
 
                doh = ip_vs_dest_conn_overhead(dest);
-               if ((loh * atomic_read(&dest->weight) >
-                    doh * atomic_read(&least->weight))
+               if (((__s64)loh * atomic_read(&dest->weight) >
+                    (__s64)doh * atomic_read(&least->weight))
                    && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
                        least = dest;
                        loh = doh;
@@ -232,7 +222,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
 
        /* select the first destination server, whose weight > 0 */
        list_for_each_entry(e, &set->list, list) {
-               most = rcu_dereference_protected(e->dest, 1);
+               most = e->dest;
                if (atomic_read(&most->weight) > 0) {
                        moh = ip_vs_dest_conn_overhead(most);
                        goto nextstage;
@@ -243,11 +233,11 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
        /* find the destination with the weighted most load */
   nextstage:
        list_for_each_entry_continue(e, &set->list, list) {
-               dest = rcu_dereference_protected(e->dest, 1);
+               dest = e->dest;
                doh = ip_vs_dest_conn_overhead(dest);
                /* moh/mw < doh/dw ==> moh*dw < doh*mw, where mw,dw>0 */
-               if ((moh * atomic_read(&dest->weight) <
-                    doh * atomic_read(&most->weight))
+               if (((__s64)moh * atomic_read(&dest->weight) <
+                    (__s64)doh * atomic_read(&most->weight))
                    && (atomic_read(&dest->weight) > 0)) {
                        most = dest;
                        moh = doh;
@@ -611,8 +601,8 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc)
                        continue;
 
                doh = ip_vs_dest_conn_overhead(dest);
-               if (loh * atomic_read(&dest->weight) >
-                   doh * atomic_read(&least->weight)) {
+               if ((__s64)loh * atomic_read(&dest->weight) >
+                   (__s64)doh * atomic_read(&least->weight)) {
                        least = dest;
                        loh = doh;
                }
@@ -819,7 +809,7 @@ static void __exit ip_vs_lblcr_cleanup(void)
 {
        unregister_ip_vs_scheduler(&ip_vs_lblcr_scheduler);
        unregister_pernet_subsys(&ip_vs_lblcr_ops);
-       synchronize_rcu();
+       rcu_barrier();
 }
 
 
index d8d9860934fee1e7f59505eeefa094307b2d58c3..961a6de9bb29035458945185f488a5fc1209ba00 100644 (file)
@@ -40,7 +40,7 @@
 #include <net/ip_vs.h>
 
 
-static inline unsigned int
+static inline int
 ip_vs_nq_dest_overhead(struct ip_vs_dest *dest)
 {
        /*
@@ -59,7 +59,7 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                  struct ip_vs_iphdr *iph)
 {
        struct ip_vs_dest *dest, *least = NULL;
-       unsigned int loh = 0, doh;
+       int loh = 0, doh;
 
        IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
 
@@ -92,8 +92,8 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                }
 
                if (!least ||
-                   (loh * atomic_read(&dest->weight) >
-                    doh * atomic_read(&least->weight))) {
+                   ((__s64)loh * atomic_read(&dest->weight) >
+                    (__s64)doh * atomic_read(&least->weight))) {
                        least = dest;
                        loh = doh;
                }
index a5284cc3d88279923b6a28b1f8a8f87bfc2a6a0f..e446b9fa7424c6382cb65433447f3febe2b17eeb 100644 (file)
@@ -44,7 +44,7 @@
 #include <net/ip_vs.h>
 
 
-static inline unsigned int
+static inline int
 ip_vs_sed_dest_overhead(struct ip_vs_dest *dest)
 {
        /*
@@ -63,7 +63,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                   struct ip_vs_iphdr *iph)
 {
        struct ip_vs_dest *dest, *least;
-       unsigned int loh, doh;
+       int loh, doh;
 
        IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
 
@@ -99,8 +99,8 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                if (dest->flags & IP_VS_DEST_F_OVERLOAD)
                        continue;
                doh = ip_vs_sed_dest_overhead(dest);
-               if (loh * atomic_read(&dest->weight) >
-                   doh * atomic_read(&least->weight)) {
+               if ((__s64)loh * atomic_read(&dest->weight) >
+                   (__s64)doh * atomic_read(&least->weight)) {
                        least = dest;
                        loh = doh;
                }
index 6dc1fa1288409067de8a19f53a32e174caa9adc9..b5b4650d50a9180f211e6cce82e3393ece2fc11c 100644 (file)
@@ -35,7 +35,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                   struct ip_vs_iphdr *iph)
 {
        struct ip_vs_dest *dest, *least;
-       unsigned int loh, doh;
+       int loh, doh;
 
        IP_VS_DBG(6, "ip_vs_wlc_schedule(): Scheduling...\n");
 
@@ -71,8 +71,8 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
                if (dest->flags & IP_VS_DEST_F_OVERLOAD)
                        continue;
                doh = ip_vs_dest_conn_overhead(dest);
-               if (loh * atomic_read(&dest->weight) >
-                   doh * atomic_read(&least->weight)) {
+               if ((__s64)loh * atomic_read(&dest->weight) >
+                   (__s64)doh * atomic_read(&least->weight)) {
                        least = dest;
                        loh = doh;
                }
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 6fd967c6278c86fbc81ad232035891656750330a..cdf4567ba9b330929aec53eb1c75d57a7047106e 100644 (file)
@@ -24,7 +24,7 @@
 int synproxy_net_id;
 EXPORT_SYMBOL_GPL(synproxy_net_id);
 
-void
+bool
 synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
                       const struct tcphdr *th, struct synproxy_options *opts)
 {
@@ -32,7 +32,8 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
        u8 buf[40], *ptr;
 
        ptr = skb_header_pointer(skb, doff + sizeof(*th), length, buf);
-       BUG_ON(ptr == NULL);
+       if (ptr == NULL)
+               return false;
 
        opts->options = 0;
        while (length > 0) {
@@ -41,16 +42,16 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
 
                switch (opcode) {
                case TCPOPT_EOL:
-                       return;
+                       return true;
                case TCPOPT_NOP:
                        length--;
                        continue;
                default:
                        opsize = *ptr++;
                        if (opsize < 2)
-                               return;
+                               return true;
                        if (opsize > length)
-                               return;
+                               return true;
 
                        switch (opcode) {
                        case TCPOPT_MSS:
@@ -84,6 +85,7 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
                        length -= opsize;
                }
        }
+       return true;
 }
 EXPORT_SYMBOL_GPL(synproxy_parse_options);
 
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 a17dda1bbee0704935c92c7d265268fb73c724a1..8df7f64c6db35a0f538bef1fa0206f7826fd1a14 100644 (file)
@@ -168,16 +168,43 @@ int netlink_remove_tap(struct netlink_tap *nt)
 }
 EXPORT_SYMBOL_GPL(netlink_remove_tap);
 
+static bool netlink_filter_tap(const struct sk_buff *skb)
+{
+       struct sock *sk = skb->sk;
+       bool pass = false;
+
+       /* We take the more conservative approach and
+        * whitelist socket protocols that may pass.
+        */
+       switch (sk->sk_protocol) {
+       case NETLINK_ROUTE:
+       case NETLINK_USERSOCK:
+       case NETLINK_SOCK_DIAG:
+       case NETLINK_NFLOG:
+       case NETLINK_XFRM:
+       case NETLINK_FIB_LOOKUP:
+       case NETLINK_NETFILTER:
+       case NETLINK_GENERIC:
+               pass = true;
+               break;
+       }
+
+       return pass;
+}
+
 static int __netlink_deliver_tap_skb(struct sk_buff *skb,
                                     struct net_device *dev)
 {
        struct sk_buff *nskb;
+       struct sock *sk = skb->sk;
        int ret = -ENOMEM;
 
        dev_hold(dev);
        nskb = skb_clone(skb, GFP_ATOMIC);
        if (nskb) {
                nskb->dev = dev;
+               nskb->protocol = htons((u16) sk->sk_protocol);
+
                ret = dev_queue_xmit(nskb);
                if (unlikely(ret > 0))
                        ret = net_xmit_errno(ret);
@@ -192,6 +219,9 @@ static void __netlink_deliver_tap(struct sk_buff *skb)
        int ret;
        struct netlink_tap *tmp;
 
+       if (!netlink_filter_tap(skb))
+               return;
+
        list_for_each_entry_rcu(tmp, &netlink_tap_all, list) {
                ret = __netlink_deliver_tap_skb(skb, tmp->dev);
                if (unlikely(ret))
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 32ad015ee8ce4a9c5b967c22dd90631881f2362b..a2fef8b10b960c15d29556b7dc832737c848b3b6 100644 (file)
@@ -285,7 +285,7 @@ static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q)
 
 
 /* remove one skb from head of flow queue */
-static struct sk_buff *fq_dequeue_head(struct fq_flow *flow)
+static struct sk_buff *fq_dequeue_head(struct Qdisc *sch, struct fq_flow *flow)
 {
        struct sk_buff *skb = flow->head;
 
@@ -293,6 +293,8 @@ static struct sk_buff *fq_dequeue_head(struct fq_flow *flow)
                flow->head = skb->next;
                skb->next = NULL;
                flow->qlen--;
+               sch->qstats.backlog -= qdisc_pkt_len(skb);
+               sch->q.qlen--;
        }
        return skb;
 }
@@ -418,8 +420,9 @@ static struct sk_buff *fq_dequeue(struct Qdisc *sch)
        struct fq_flow_head *head;
        struct sk_buff *skb;
        struct fq_flow *f;
+       u32 rate;
 
-       skb = fq_dequeue_head(&q->internal);
+       skb = fq_dequeue_head(sch, &q->internal);
        if (skb)
                goto out;
        fq_check_throttled(q, now);
@@ -449,7 +452,7 @@ begin:
                goto begin;
        }
 
-       skb = fq_dequeue_head(f);
+       skb = fq_dequeue_head(sch, f);
        if (!skb) {
                head->first = f->next;
                /* force a pass through old_flows to prevent starvation */
@@ -466,43 +469,74 @@ begin:
        f->time_next_packet = now;
        f->credit -= qdisc_pkt_len(skb);
 
-       if (f->credit <= 0 &&
-           q->rate_enable &&
-           skb->sk && skb->sk->sk_state != TCP_TIME_WAIT) {
-               u32 rate = skb->sk->sk_pacing_rate ?: q->flow_default_rate;
+       if (f->credit > 0 || !q->rate_enable)
+               goto out;
 
-               rate = min(rate, q->flow_max_rate);
-               if (rate) {
-                       u64 len = (u64)qdisc_pkt_len(skb) * NSEC_PER_SEC;
-
-                       do_div(len, rate);
-                       /* Since socket rate can change later,
-                        * clamp the delay to 125 ms.
-                        * TODO: maybe segment the too big skb, as in commit
-                        * e43ac79a4bc ("sch_tbf: segment too big GSO packets")
-                        */
-                       if (unlikely(len > 125 * NSEC_PER_MSEC)) {
-                               len = 125 * NSEC_PER_MSEC;
-                               q->stat_pkts_too_long++;
-                       }
+       if (skb->sk && skb->sk->sk_state != TCP_TIME_WAIT) {
+               rate = skb->sk->sk_pacing_rate ?: q->flow_default_rate;
 
-                       f->time_next_packet = now + len;
+               rate = min(rate, q->flow_max_rate);
+       } else {
+               rate = q->flow_max_rate;
+               if (rate == ~0U)
+                       goto out;
+       }
+       if (rate) {
+               u32 plen = max(qdisc_pkt_len(skb), q->quantum);
+               u64 len = (u64)plen * NSEC_PER_SEC;
+
+               do_div(len, rate);
+               /* Since socket rate can change later,
+                * clamp the delay to 125 ms.
+                * TODO: maybe segment the too big skb, as in commit
+                * e43ac79a4bc ("sch_tbf: segment too big GSO packets")
+                */
+               if (unlikely(len > 125 * NSEC_PER_MSEC)) {
+                       len = 125 * NSEC_PER_MSEC;
+                       q->stat_pkts_too_long++;
                }
+
+               f->time_next_packet = now + len;
        }
 out:
-       sch->qstats.backlog -= qdisc_pkt_len(skb);
        qdisc_bstats_update(sch, skb);
-       sch->q.qlen--;
        qdisc_unthrottled(sch);
        return skb;
 }
 
 static void fq_reset(struct Qdisc *sch)
 {
+       struct fq_sched_data *q = qdisc_priv(sch);
+       struct rb_root *root;
        struct sk_buff *skb;
+       struct rb_node *p;
+       struct fq_flow *f;
+       unsigned int idx;
 
-       while ((skb = fq_dequeue(sch)) != NULL)
+       while ((skb = fq_dequeue_head(sch, &q->internal)) != NULL)
                kfree_skb(skb);
+
+       if (!q->fq_root)
+               return;
+
+       for (idx = 0; idx < (1U << q->fq_trees_log); idx++) {
+               root = &q->fq_root[idx];
+               while ((p = rb_first(root)) != NULL) {
+                       f = container_of(p, struct fq_flow, fq_node);
+                       rb_erase(p, root);
+
+                       while ((skb = fq_dequeue_head(sch, f)) != NULL)
+                               kfree_skb(skb);
+
+                       kmem_cache_free(fq_flow_cachep, f);
+               }
+       }
+       q->new_flows.first      = NULL;
+       q->old_flows.first      = NULL;
+       q->delayed              = RB_ROOT;
+       q->flows                = 0;
+       q->inactive_flows       = 0;
+       q->throttled_flows      = 0;
 }
 
 static void fq_rehash(struct fq_sched_data *q,
@@ -645,6 +679,8 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = fq_dequeue(sch);
 
+               if (!skb)
+                       break;
                kfree_skb(skb);
                drop_count++;
        }
@@ -657,21 +693,9 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
 static void fq_destroy(struct Qdisc *sch)
 {
        struct fq_sched_data *q = qdisc_priv(sch);
-       struct rb_root *root;
-       struct rb_node *p;
-       unsigned int idx;
 
-       if (q->fq_root) {
-               for (idx = 0; idx < (1U << q->fq_trees_log); idx++) {
-                       root = &q->fq_root[idx];
-                       while ((p = rb_first(root)) != NULL) {
-                               rb_erase(p, root);
-                               kmem_cache_free(fq_flow_cachep,
-                                               container_of(p, struct fq_flow, fq_node));
-                       }
-               }
-               kfree(q->fq_root);
-       }
+       fq_reset(sch);
+       kfree(q->fq_root);
        qdisc_watchdog_cancel(&q->watchdog);
 }
 
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..084656671d6ee4cebc6220ad0d92bae654497882 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 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 void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt,
-                                          struct rpc_auth *auth)
+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,112 @@ 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);
 }
 
+/*
+ * Auths may be shared between rpc clients that were cloned from a
+ * common client with the same xprt, if they also share the flavor and
+ * target_name.
+ *
+ * The auth is looked up from the oldest parent sharing the same
+ * cl_xprt, and the auth itself references only that common parent
+ * (which is guaranteed to last as long as any of its descendants).
+ */
+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->client != clnt)
+                       continue;
+               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 +1309,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 +1347,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 +1512,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 +1528,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 +1546,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 +1880,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 +1896,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 +1984,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 9bc6db04be3ea7cd998f41187ff40b19baa9c920..e7000be321b0148469264524ed6fce75c3952955 100644 (file)
@@ -47,12 +47,12 @@ static int net_ctl_permissions(struct ctl_table_header *head,
 
        /* Allow network administrator to have same access as root. */
        if (ns_capable(net->user_ns, CAP_NET_ADMIN) ||
-           uid_eq(root_uid, current_uid())) {
+           uid_eq(root_uid, current_euid())) {
                int mode = (table->mode >> 6) & 7;
                return (mode << 6) | (mode << 3) | mode;
        }
        /* Allow netns root group to have the same access as the root group */
-       if (gid_eq(root_gid, current_gid())) {
+       if (in_egroup_p(root_gid)) {
                int mode = (table->mode >> 3) & 7;
                return (mode << 3) | mode;
        }
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..66cad506b8a2a944f2873856ef0078445f673b8b 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 (CHK("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 9b9013b2e3211a9c6de17a9001e7939a73bf48e9..d49c53960b60c5010d314022d3e58d255ffac204 100644 (file)
@@ -29,3 +29,15 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE
          boot.
 
          If you are unsure how to answer this question, answer 1.
+
+config SECURITY_APPARMOR_HASH
+       bool "SHA1 hash of loaded profiles"
+       depends on SECURITY_APPARMOR
+       depends on CRYPTO
+       select CRYPTO_SHA1
+       default y
+
+       help
+         This option selects whether sha1 hashing is done against loaded
+          profiles and exported for inspection to user space via the apparmor
+          filesystem.
index 5706b74c857f550a2515dc445164063154a12cac..d693df87481837fa8d2fb95137d54f3b155cc280 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
               path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
               resource.o sid.o file.o
+apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
 
 clean-files := capability_names.h rlim_names.h
 
@@ -18,7 +19,11 @@ quiet_cmd_make-caps = GEN     $@
 cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
        sed $< >>$@ -r -n -e '/CAP_FS_MASK/d' \
        -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\
-       echo "};" >> $@
+       echo "};" >> $@ ;\
+       echo -n '\#define AA_FS_CAPS_MASK "' >> $@ ;\
+       sed $< -r -n -e '/CAP_FS_MASK/d' \
+           -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
+            tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
 
 
 # Build a lower case string table of rlimit names.
index 16c15ec6f67078238d25e10f3ea6fc3b7e243b88..7db9954f1af2c56c42400746f367f5f4d9906ca8 100644 (file)
@@ -12,6 +12,7 @@
  * License.
  */
 
+#include <linux/ctype.h>
 #include <linux/security.h>
 #include <linux/vmalloc.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
 #include <linux/namei.h>
 #include <linux/capability.h>
+#include <linux/rcupdate.h>
 
 #include "include/apparmor.h"
 #include "include/apparmorfs.h"
 #include "include/audit.h"
 #include "include/context.h"
+#include "include/crypto.h"
 #include "include/policy.h"
 #include "include/resource.h"
 
+/**
+ * aa_mangle_name - mangle a profile name to std profile layout form
+ * @name: profile name to mangle  (NOT NULL)
+ * @target: buffer to store mangled name, same length as @name (MAYBE NULL)
+ *
+ * Returns: length of mangled name
+ */
+static int mangle_name(char *name, char *target)
+{
+       char *t = target;
+
+       while (*name == '/' || *name == '.')
+               name++;
+
+       if (target) {
+               for (; *name; name++) {
+                       if (*name == '/')
+                               *(t)++ = '.';
+                       else if (isspace(*name))
+                               *(t)++ = '_';
+                       else if (isalnum(*name) || strchr("._-", *name))
+                               *(t)++ = *name;
+               }
+
+               *t = 0;
+       } else {
+               int len = 0;
+               for (; *name; name++) {
+                       if (isalnum(*name) || isspace(*name) ||
+                           strchr("/._-", *name))
+                               len++;
+               }
+
+               return len;
+       }
+
+       return t - target;
+}
+
 /**
  * aa_simple_write_to_buffer - common routine for getting policy from user
  * @op: operation doing the user buffer copy
@@ -182,8 +224,565 @@ const struct file_operations aa_fs_seq_file_ops = {
        .release        = single_release,
 };
 
-/** Base file system setup **/
+static int aa_fs_seq_profile_open(struct inode *inode, struct file *file,
+                                 int (*show)(struct seq_file *, void *))
+{
+       struct aa_replacedby *r = aa_get_replacedby(inode->i_private);
+       int error = single_open(file, show, r);
+
+       if (error) {
+               file->private_data = NULL;
+               aa_put_replacedby(r);
+       }
+
+       return error;
+}
+
+static int aa_fs_seq_profile_release(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq = (struct seq_file *) file->private_data;
+       if (seq)
+               aa_put_replacedby(seq->private);
+       return single_release(inode, file);
+}
+
+static int aa_fs_seq_profname_show(struct seq_file *seq, void *v)
+{
+       struct aa_replacedby *r = seq->private;
+       struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
+       seq_printf(seq, "%s\n", profile->base.name);
+       aa_put_profile(profile);
+
+       return 0;
+}
+
+static int aa_fs_seq_profname_open(struct inode *inode, struct file *file)
+{
+       return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profname_show);
+}
+
+static const struct file_operations aa_fs_profname_fops = {
+       .owner          = THIS_MODULE,
+       .open           = aa_fs_seq_profname_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = aa_fs_seq_profile_release,
+};
+
+static int aa_fs_seq_profmode_show(struct seq_file *seq, void *v)
+{
+       struct aa_replacedby *r = seq->private;
+       struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
+       seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]);
+       aa_put_profile(profile);
+
+       return 0;
+}
+
+static int aa_fs_seq_profmode_open(struct inode *inode, struct file *file)
+{
+       return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profmode_show);
+}
+
+static const struct file_operations aa_fs_profmode_fops = {
+       .owner          = THIS_MODULE,
+       .open           = aa_fs_seq_profmode_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = aa_fs_seq_profile_release,
+};
+
+static int aa_fs_seq_profattach_show(struct seq_file *seq, void *v)
+{
+       struct aa_replacedby *r = seq->private;
+       struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
+       if (profile->attach)
+               seq_printf(seq, "%s\n", profile->attach);
+       else if (profile->xmatch)
+               seq_puts(seq, "<unknown>\n");
+       else
+               seq_printf(seq, "%s\n", profile->base.name);
+       aa_put_profile(profile);
+
+       return 0;
+}
+
+static int aa_fs_seq_profattach_open(struct inode *inode, struct file *file)
+{
+       return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profattach_show);
+}
+
+static const struct file_operations aa_fs_profattach_fops = {
+       .owner          = THIS_MODULE,
+       .open           = aa_fs_seq_profattach_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = aa_fs_seq_profile_release,
+};
+
+static int aa_fs_seq_hash_show(struct seq_file *seq, void *v)
+{
+       struct aa_replacedby *r = seq->private;
+       struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
+       unsigned int i, size = aa_hash_size();
+
+       if (profile->hash) {
+               for (i = 0; i < size; i++)
+                       seq_printf(seq, "%.2x", profile->hash[i]);
+               seq_puts(seq, "\n");
+       }
+
+       return 0;
+}
+
+static int aa_fs_seq_hash_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, aa_fs_seq_hash_show, inode->i_private);
+}
+
+static const struct file_operations aa_fs_seq_hash_fops = {
+       .owner          = THIS_MODULE,
+       .open           = aa_fs_seq_hash_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/** fns to setup dynamic per profile/namespace files **/
+void __aa_fs_profile_rmdir(struct aa_profile *profile)
+{
+       struct aa_profile *child;
+       int i;
+
+       if (!profile)
+               return;
+
+       list_for_each_entry(child, &profile->base.profiles, base.list)
+               __aa_fs_profile_rmdir(child);
+
+       for (i = AAFS_PROF_SIZEOF - 1; i >= 0; --i) {
+               struct aa_replacedby *r;
+               if (!profile->dents[i])
+                       continue;
+
+               r = profile->dents[i]->d_inode->i_private;
+               securityfs_remove(profile->dents[i]);
+               aa_put_replacedby(r);
+               profile->dents[i] = NULL;
+       }
+}
+
+void __aa_fs_profile_migrate_dents(struct aa_profile *old,
+                                  struct aa_profile *new)
+{
+       int i;
+
+       for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
+               new->dents[i] = old->dents[i];
+               old->dents[i] = NULL;
+       }
+}
+
+static struct dentry *create_profile_file(struct dentry *dir, const char *name,
+                                         struct aa_profile *profile,
+                                         const struct file_operations *fops)
+{
+       struct aa_replacedby *r = aa_get_replacedby(profile->replacedby);
+       struct dentry *dent;
+
+       dent = securityfs_create_file(name, S_IFREG | 0444, dir, r, fops);
+       if (IS_ERR(dent))
+               aa_put_replacedby(r);
+
+       return dent;
+}
+
+/* requires lock be held */
+int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
+{
+       struct aa_profile *child;
+       struct dentry *dent = NULL, *dir;
+       int error;
+
+       if (!parent) {
+               struct aa_profile *p;
+               p = aa_deref_parent(profile);
+               dent = prof_dir(p);
+               /* adding to parent that previously didn't have children */
+               dent = securityfs_create_dir("profiles", dent);
+               if (IS_ERR(dent))
+                       goto fail;
+               prof_child_dir(p) = parent = dent;
+       }
+
+       if (!profile->dirname) {
+               int len, id_len;
+               len = mangle_name(profile->base.name, NULL);
+               id_len = snprintf(NULL, 0, ".%ld", profile->ns->uniq_id);
+
+               profile->dirname = kmalloc(len + id_len + 1, GFP_KERNEL);
+               if (!profile->dirname)
+                       goto fail;
+
+               mangle_name(profile->base.name, profile->dirname);
+               sprintf(profile->dirname + len, ".%ld", profile->ns->uniq_id++);
+       }
+
+       dent = securityfs_create_dir(profile->dirname, parent);
+       if (IS_ERR(dent))
+               goto fail;
+       prof_dir(profile) = dir = dent;
+
+       dent = create_profile_file(dir, "name", profile, &aa_fs_profname_fops);
+       if (IS_ERR(dent))
+               goto fail;
+       profile->dents[AAFS_PROF_NAME] = dent;
+
+       dent = create_profile_file(dir, "mode", profile, &aa_fs_profmode_fops);
+       if (IS_ERR(dent))
+               goto fail;
+       profile->dents[AAFS_PROF_MODE] = dent;
+
+       dent = create_profile_file(dir, "attach", profile,
+                                  &aa_fs_profattach_fops);
+       if (IS_ERR(dent))
+               goto fail;
+       profile->dents[AAFS_PROF_ATTACH] = dent;
+
+       if (profile->hash) {
+               dent = create_profile_file(dir, "sha1", profile,
+                                          &aa_fs_seq_hash_fops);
+               if (IS_ERR(dent))
+                       goto fail;
+               profile->dents[AAFS_PROF_HASH] = dent;
+       }
+
+       list_for_each_entry(child, &profile->base.profiles, base.list) {
+               error = __aa_fs_profile_mkdir(child, prof_child_dir(profile));
+               if (error)
+                       goto fail2;
+       }
+
+       return 0;
+
+fail:
+       error = PTR_ERR(dent);
+
+fail2:
+       __aa_fs_profile_rmdir(profile);
+
+       return error;
+}
+
+void __aa_fs_namespace_rmdir(struct aa_namespace *ns)
+{
+       struct aa_namespace *sub;
+       struct aa_profile *child;
+       int i;
+
+       if (!ns)
+               return;
+
+       list_for_each_entry(child, &ns->base.profiles, base.list)
+               __aa_fs_profile_rmdir(child);
+
+       list_for_each_entry(sub, &ns->sub_ns, base.list) {
+               mutex_lock(&sub->lock);
+               __aa_fs_namespace_rmdir(sub);
+               mutex_unlock(&sub->lock);
+       }
 
+       for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) {
+               securityfs_remove(ns->dents[i]);
+               ns->dents[i] = NULL;
+       }
+}
+
+int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent,
+                           const char *name)
+{
+       struct aa_namespace *sub;
+       struct aa_profile *child;
+       struct dentry *dent, *dir;
+       int error;
+
+       if (!name)
+               name = ns->base.name;
+
+       dent = securityfs_create_dir(name, parent);
+       if (IS_ERR(dent))
+               goto fail;
+       ns_dir(ns) = dir = dent;
+
+       dent = securityfs_create_dir("profiles", dir);
+       if (IS_ERR(dent))
+               goto fail;
+       ns_subprofs_dir(ns) = dent;
+
+       dent = securityfs_create_dir("namespaces", dir);
+       if (IS_ERR(dent))
+               goto fail;
+       ns_subns_dir(ns) = dent;
+
+       list_for_each_entry(child, &ns->base.profiles, base.list) {
+               error = __aa_fs_profile_mkdir(child, ns_subprofs_dir(ns));
+               if (error)
+                       goto fail2;
+       }
+
+       list_for_each_entry(sub, &ns->sub_ns, base.list) {
+               mutex_lock(&sub->lock);
+               error = __aa_fs_namespace_mkdir(sub, ns_subns_dir(ns), NULL);
+               mutex_unlock(&sub->lock);
+               if (error)
+                       goto fail2;
+       }
+
+       return 0;
+
+fail:
+       error = PTR_ERR(dent);
+
+fail2:
+       __aa_fs_namespace_rmdir(ns);
+
+       return error;
+}
+
+
+#define list_entry_next(pos, member) \
+       list_entry(pos->member.next, typeof(*pos), member)
+#define list_entry_is_head(pos, head, member) (&pos->member == (head))
+
+/**
+ * __next_namespace - find the next namespace to list
+ * @root: root namespace to stop search at (NOT NULL)
+ * @ns: current ns position (NOT NULL)
+ *
+ * Find the next namespace from @ns under @root and handle all locking needed
+ * while switching current namespace.
+ *
+ * Returns: next namespace or NULL if at last namespace under @root
+ * Requires: ns->parent->lock to be held
+ * NOTE: will not unlock root->lock
+ */
+static struct aa_namespace *__next_namespace(struct aa_namespace *root,
+                                            struct aa_namespace *ns)
+{
+       struct aa_namespace *parent, *next;
+
+       /* is next namespace a child */
+       if (!list_empty(&ns->sub_ns)) {
+               next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
+               mutex_lock(&next->lock);
+               return next;
+       }
+
+       /* check if the next ns is a sibling, parent, gp, .. */
+       parent = ns->parent;
+       while (ns != root) {
+               mutex_unlock(&ns->lock);
+               next = list_entry_next(ns, base.list);
+               if (!list_entry_is_head(next, &parent->sub_ns, base.list)) {
+                       mutex_lock(&next->lock);
+                       return next;
+               }
+               ns = parent;
+               parent = parent->parent;
+       }
+
+       return NULL;
+}
+
+/**
+ * __first_profile - find the first profile in a namespace
+ * @root: namespace that is root of profiles being displayed (NOT NULL)
+ * @ns: namespace to start in   (NOT NULL)
+ *
+ * Returns: unrefcounted profile or NULL if no profile
+ * Requires: profile->ns.lock to be held
+ */
+static struct aa_profile *__first_profile(struct aa_namespace *root,
+                                         struct aa_namespace *ns)
+{
+       for (; ns; ns = __next_namespace(root, ns)) {
+               if (!list_empty(&ns->base.profiles))
+                       return list_first_entry(&ns->base.profiles,
+                                               struct aa_profile, base.list);
+       }
+       return NULL;
+}
+
+/**
+ * __next_profile - step to the next profile in a profile tree
+ * @profile: current profile in tree (NOT NULL)
+ *
+ * Perform a depth first traversal on the profile tree in a namespace
+ *
+ * Returns: next profile or NULL if done
+ * Requires: profile->ns.lock to be held
+ */
+static struct aa_profile *__next_profile(struct aa_profile *p)
+{
+       struct aa_profile *parent;
+       struct aa_namespace *ns = p->ns;
+
+       /* is next profile a child */
+       if (!list_empty(&p->base.profiles))
+               return list_first_entry(&p->base.profiles, typeof(*p),
+                                       base.list);
+
+       /* is next profile a sibling, parent sibling, gp, sibling, .. */
+       parent = rcu_dereference_protected(p->parent,
+                                          mutex_is_locked(&p->ns->lock));
+       while (parent) {
+               p = list_entry_next(p, base.list);
+               if (!list_entry_is_head(p, &parent->base.profiles, base.list))
+                       return p;
+               p = parent;
+               parent = rcu_dereference_protected(parent->parent,
+                                           mutex_is_locked(&parent->ns->lock));
+       }
+
+       /* is next another profile in the namespace */
+       p = list_entry_next(p, base.list);
+       if (!list_entry_is_head(p, &ns->base.profiles, base.list))
+               return p;
+
+       return NULL;
+}
+
+/**
+ * next_profile - step to the next profile in where ever it may be
+ * @root: root namespace  (NOT NULL)
+ * @profile: current profile  (NOT NULL)
+ *
+ * Returns: next profile or NULL if there isn't one
+ */
+static struct aa_profile *next_profile(struct aa_namespace *root,
+                                      struct aa_profile *profile)
+{
+       struct aa_profile *next = __next_profile(profile);
+       if (next)
+               return next;
+
+       /* finished all profiles in namespace move to next namespace */
+       return __first_profile(root, __next_namespace(root, profile->ns));
+}
+
+/**
+ * p_start - start a depth first traversal of profile tree
+ * @f: seq_file to fill
+ * @pos: current position
+ *
+ * Returns: first profile under current namespace or NULL if none found
+ *
+ * acquires first ns->lock
+ */
+static void *p_start(struct seq_file *f, loff_t *pos)
+{
+       struct aa_profile *profile = NULL;
+       struct aa_namespace *root = aa_current_profile()->ns;
+       loff_t l = *pos;
+       f->private = aa_get_namespace(root);
+
+
+       /* find the first profile */
+       mutex_lock(&root->lock);
+       profile = __first_profile(root, root);
+
+       /* skip to position */
+       for (; profile && l > 0; l--)
+               profile = next_profile(root, profile);
+
+       return profile;
+}
+
+/**
+ * p_next - read the next profile entry
+ * @f: seq_file to fill
+ * @p: profile previously returned
+ * @pos: current position
+ *
+ * Returns: next profile after @p or NULL if none
+ *
+ * may acquire/release locks in namespace tree as necessary
+ */
+static void *p_next(struct seq_file *f, void *p, loff_t *pos)
+{
+       struct aa_profile *profile = p;
+       struct aa_namespace *ns = f->private;
+       (*pos)++;
+
+       return next_profile(ns, profile);
+}
+
+/**
+ * p_stop - stop depth first traversal
+ * @f: seq_file we are filling
+ * @p: the last profile writen
+ *
+ * Release all locking done by p_start/p_next on namespace tree
+ */
+static void p_stop(struct seq_file *f, void *p)
+{
+       struct aa_profile *profile = p;
+       struct aa_namespace *root = f->private, *ns;
+
+       if (profile) {
+               for (ns = profile->ns; ns && ns != root; ns = ns->parent)
+                       mutex_unlock(&ns->lock);
+       }
+       mutex_unlock(&root->lock);
+       aa_put_namespace(root);
+}
+
+/**
+ * seq_show_profile - show a profile entry
+ * @f: seq_file to file
+ * @p: current position (profile)    (NOT NULL)
+ *
+ * Returns: error on failure
+ */
+static int seq_show_profile(struct seq_file *f, void *p)
+{
+       struct aa_profile *profile = (struct aa_profile *)p;
+       struct aa_namespace *root = f->private;
+
+       if (profile->ns != root)
+               seq_printf(f, ":%s://", aa_ns_name(root, profile->ns));
+       seq_printf(f, "%s (%s)\n", profile->base.hname,
+                  aa_profile_mode_names[profile->mode]);
+
+       return 0;
+}
+
+static const struct seq_operations aa_fs_profiles_op = {
+       .start = p_start,
+       .next = p_next,
+       .stop = p_stop,
+       .show = seq_show_profile,
+};
+
+static int profiles_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &aa_fs_profiles_op);
+}
+
+static int profiles_release(struct inode *inode, struct file *file)
+{
+       return seq_release(inode, file);
+}
+
+static const struct file_operations aa_fs_profiles_fops = {
+       .open = profiles_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = profiles_release,
+};
+
+
+/** Base file system setup **/
 static struct aa_fs_entry aa_fs_entry_file[] = {
        AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \
                                  "link lock"),
@@ -198,11 +797,18 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
        { }
 };
 
+static struct aa_fs_entry aa_fs_entry_policy[] = {
+       AA_FS_FILE_BOOLEAN("set_load",          1),
+       {}
+};
+
 static struct aa_fs_entry aa_fs_entry_features[] = {
+       AA_FS_DIR("policy",                     aa_fs_entry_policy),
        AA_FS_DIR("domain",                     aa_fs_entry_domain),
        AA_FS_DIR("file",                       aa_fs_entry_file),
        AA_FS_FILE_U64("capability",            VFS_CAP_FLAGS_MASK),
        AA_FS_DIR("rlimit",                     aa_fs_entry_rlimit),
+       AA_FS_DIR("caps",                       aa_fs_entry_caps),
        { }
 };
 
@@ -210,6 +816,7 @@ static struct aa_fs_entry aa_fs_entry_apparmor[] = {
        AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load),
        AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
        AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove),
+       AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops),
        AA_FS_DIR("features", aa_fs_entry_features),
        { }
 };
@@ -240,6 +847,7 @@ static int __init aafs_create_file(struct aa_fs_entry *fs_file,
        return error;
 }
 
+static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir);
 /**
  * aafs_create_dir - recursively create a directory entry in the securityfs
  * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL)
@@ -250,17 +858,16 @@ static int __init aafs_create_file(struct aa_fs_entry *fs_file,
 static int __init aafs_create_dir(struct aa_fs_entry *fs_dir,
                                  struct dentry *parent)
 {
-       int error;
        struct aa_fs_entry *fs_file;
+       struct dentry *dir;
+       int error;
 
-       fs_dir->dentry = securityfs_create_dir(fs_dir->name, parent);
-       if (IS_ERR(fs_dir->dentry)) {
-               error = PTR_ERR(fs_dir->dentry);
-               fs_dir->dentry = NULL;
-               goto failed;
-       }
+       dir = securityfs_create_dir(fs_dir->name, parent);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+       fs_dir->dentry = dir;
 
-       for (fs_file = fs_dir->v.files; fs_file->name; ++fs_file) {
+       for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
                if (fs_file->v_type == AA_FS_TYPE_DIR)
                        error = aafs_create_dir(fs_file, fs_dir->dentry);
                else
@@ -272,6 +879,8 @@ static int __init aafs_create_dir(struct aa_fs_entry *fs_dir,
        return 0;
 
 failed:
+       aafs_remove_dir(fs_dir);
+
        return error;
 }
 
@@ -296,7 +905,7 @@ static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir)
 {
        struct aa_fs_entry *fs_file;
 
-       for (fs_file = fs_dir->v.files; fs_file->name; ++fs_file) {
+       for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
                if (fs_file->v_type == AA_FS_TYPE_DIR)
                        aafs_remove_dir(fs_file);
                else
@@ -340,6 +949,11 @@ static int __init aa_create_aafs(void)
        if (error)
                goto error;
 
+       error = __aa_fs_namespace_mkdir(root_ns, aa_fs_entry.dentry,
+                                       "policy");
+       if (error)
+               goto error;
+
        /* TODO: add support for apparmorfs_null and apparmorfs_mnt */
 
        /* Report that AppArmor fs is enabled */
index 887a5e9489453c9a304b25759b4bed973f34fb0a..84d1f5f538778b58f0b60c48d4a55ede44ff4c4f 100644 (file)
  */
 #include "capability_names.h"
 
+struct aa_fs_entry aa_fs_entry_caps[] = {
+       AA_FS_FILE_STRING("mask", AA_FS_CAPS_MASK),
+       { }
+};
+
 struct audit_cache {
        struct aa_profile *profile;
        kernel_cap_t caps;
index d5af1d15f26d6feeec7acc5e421cbb25ca9de9ce..3064c6ced87cae69b8c2eb224e4d2ac5af9d9c79 100644 (file)
@@ -112,9 +112,9 @@ int aa_replace_current_profile(struct aa_profile *profile)
                aa_clear_task_cxt_trans(cxt);
 
        /* be careful switching cxt->profile, when racing replacement it
-        * is possible that cxt->profile->replacedby is the reference keeping
-        * @profile valid, so make sure to get its reference before dropping
-        * the reference on cxt->profile */
+        * is possible that cxt->profile->replacedby->profile is the reference
+        * keeping @profile valid, so make sure to get its reference before
+        * dropping the reference on cxt->profile */
        aa_get_profile(profile);
        aa_put_profile(cxt->profile);
        cxt->profile = profile;
@@ -175,7 +175,7 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token)
                abort_creds(new);
                return -EACCES;
        }
-       cxt->profile = aa_get_profile(aa_newest_version(profile));
+       cxt->profile = aa_get_newest_profile(profile);
        /* clear exec on switching context */
        aa_put_profile(cxt->onexec);
        cxt->onexec = NULL;
@@ -212,14 +212,8 @@ int aa_restore_previous_profile(u64 token)
        }
 
        aa_put_profile(cxt->profile);
-       cxt->profile = aa_newest_version(cxt->previous);
+       cxt->profile = aa_get_newest_profile(cxt->previous);
        BUG_ON(!cxt->profile);
-       if (unlikely(cxt->profile != cxt->previous)) {
-               aa_get_profile(cxt->profile);
-               aa_put_profile(cxt->previous);
-       }
-       /* ref has been transfered so avoid putting ref in clear_task_cxt */
-       cxt->previous = NULL;
        /* clear exec && prev information when restoring to previous context */
        aa_clear_task_cxt_trans(cxt);
 
diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c
new file mode 100644 (file)
index 0000000..532471d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy loading interface function definitions.
+ *
+ * Copyright 2013 Canonical 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, version 2 of the
+ * License.
+ *
+ * Fns to provide a checksum of policy that has been loaded this can be
+ * compared to userspace policy compiles to check loaded policy is what
+ * it should be.
+ */
+
+#include <crypto/hash.h>
+
+#include "include/apparmor.h"
+#include "include/crypto.h"
+
+static unsigned int apparmor_hash_size;
+
+static struct crypto_shash *apparmor_tfm;
+
+unsigned int aa_hash_size(void)
+{
+       return apparmor_hash_size;
+}
+
+int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
+                        size_t len)
+{
+       struct {
+               struct shash_desc shash;
+               char ctx[crypto_shash_descsize(apparmor_tfm)];
+       } desc;
+       int error = -ENOMEM;
+       u32 le32_version = cpu_to_le32(version);
+
+       if (!apparmor_tfm)
+               return 0;
+
+       profile->hash = kzalloc(apparmor_hash_size, GFP_KERNEL);
+       if (!profile->hash)
+               goto fail;
+
+       desc.shash.tfm = apparmor_tfm;
+       desc.shash.flags = 0;
+
+       error = crypto_shash_init(&desc.shash);
+       if (error)
+               goto fail;
+       error = crypto_shash_update(&desc.shash, (u8 *) &le32_version, 4);
+       if (error)
+               goto fail;
+       error = crypto_shash_update(&desc.shash, (u8 *) start, len);
+       if (error)
+               goto fail;
+       error = crypto_shash_final(&desc.shash, profile->hash);
+       if (error)
+               goto fail;
+
+       return 0;
+
+fail:
+       kfree(profile->hash);
+       profile->hash = NULL;
+
+       return error;
+}
+
+static int __init init_profile_hash(void)
+{
+       struct crypto_shash *tfm;
+
+       if (!apparmor_initialized)
+               return 0;
+
+       tfm = crypto_alloc_shash("sha1", 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(tfm)) {
+               int error = PTR_ERR(tfm);
+               AA_ERROR("failed to setup profile sha1 hashing: %d\n", error);
+               return error;
+       }
+       apparmor_tfm = tfm;
+       apparmor_hash_size = crypto_shash_digestsize(apparmor_tfm);
+
+       aa_info_message("AppArmor sha1 policy hashing enabled");
+
+       return 0;
+}
+
+late_initcall(init_profile_hash);
index 01b7bd669a88d8d130f32097d0d3200a6068cbe5..26c607c971f5656da192698602dbdb85afcfa8f1 100644 (file)
@@ -144,7 +144,7 @@ static struct aa_profile *__attach_match(const char *name,
        int len = 0;
        struct aa_profile *profile, *candidate = NULL;
 
-       list_for_each_entry(profile, head, base.list) {
+       list_for_each_entry_rcu(profile, head, base.list) {
                if (profile->flags & PFLAG_NULL)
                        continue;
                if (profile->xmatch && profile->xmatch_len > len) {
@@ -177,9 +177,9 @@ static struct aa_profile *find_attach(struct aa_namespace *ns,
 {
        struct aa_profile *profile;
 
-       read_lock(&ns->lock);
+       rcu_read_lock();
        profile = aa_get_profile(__attach_match(name, list));
-       read_unlock(&ns->lock);
+       rcu_read_unlock();
 
        return profile;
 }
@@ -359,7 +359,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
        cxt = cred_cxt(bprm->cred);
        BUG_ON(!cxt);
 
-       profile = aa_get_profile(aa_newest_version(cxt->profile));
+       profile = aa_get_newest_profile(cxt->profile);
        /*
         * get the namespace from the replacement profile as replacement
         * can change the namespace
@@ -371,8 +371,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
        error = aa_path_name(&bprm->file->f_path, profile->path_flags, &buffer,
                             &name, &info);
        if (error) {
-               if (profile->flags &
-                   (PFLAG_IX_ON_NAME_ERROR | PFLAG_UNCONFINED))
+               if (unconfined(profile) ||
+                   (profile->flags & PFLAG_IX_ON_NAME_ERROR))
                        error = 0;
                name = bprm->filename;
                goto audit;
@@ -417,7 +417,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
 
                if (!(cp.allow & AA_MAY_ONEXEC))
                        goto audit;
-               new_profile = aa_get_profile(aa_newest_version(cxt->onexec));
+               new_profile = aa_get_newest_profile(cxt->onexec);
                goto apply;
        }
 
@@ -434,7 +434,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
                                new_profile = aa_get_profile(profile);
                                goto x_clear;
                        } else if (perms.xindex & AA_X_UNCONFINED) {
-                               new_profile = aa_get_profile(ns->unconfined);
+                               new_profile = aa_get_newest_profile(ns->unconfined);
                                info = "ux fallback";
                        } else {
                                error = -ENOENT;
@@ -641,7 +641,10 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
        if (count) {
                /* attempting to change into a new hat or switch to a sibling */
                struct aa_profile *root;
-               root = PROFILE_IS_HAT(profile) ? profile->parent : profile;
+               if (PROFILE_IS_HAT(profile))
+                       root = aa_get_profile_rcu(&profile->parent);
+               else
+                       root = aa_get_profile(profile);
 
                /* find first matching hat */
                for (i = 0; i < count && !hat; i++)
@@ -653,6 +656,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
                                        error = -ECHILD;
                                else
                                        error = -ENOENT;
+                               aa_put_profile(root);
                                goto out;
                        }
 
@@ -667,6 +671,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
 
                        /* freed below */
                        name = new_compound_name(root->base.hname, hats[0]);
+                       aa_put_profile(root);
                        target = name;
                        /* released below */
                        hat = aa_new_null_profile(profile, 1);
@@ -676,6 +681,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
                                goto audit;
                        }
                } else {
+                       aa_put_profile(root);
                        target = hat->base.hname;
                        if (!PROFILE_IS_HAT(hat)) {
                                info = "target not hat";
index 1ba2ca56a6efe0245327b16ee4891981746c5b7a..8fb1488a3cd4499ecf8e374dcd47f956945a0ef7 100644 (file)
@@ -78,6 +78,12 @@ static inline void *kvzalloc(size_t size)
        return __aa_kvmalloc(size, __GFP_ZERO);
 }
 
+/* returns 0 if kref not incremented */
+static inline int kref_get_not0(struct kref *kref)
+{
+       return atomic_inc_not_zero(&kref->refcount);
+}
+
 /**
  * aa_strneq - compare null terminated @str to a non null terminated substring
  * @str: a null terminated string
index 7ea4769fab3f7785c056dc0cd60e6a8f1b606c98..414e56878dd0c0462c0f85f0b0296448ad8ba27e 100644 (file)
@@ -61,4 +61,44 @@ extern const struct file_operations aa_fs_seq_file_ops;
 
 extern void __init aa_destroy_aafs(void);
 
+struct aa_profile;
+struct aa_namespace;
+
+enum aafs_ns_type {
+       AAFS_NS_DIR,
+       AAFS_NS_PROFS,
+       AAFS_NS_NS,
+       AAFS_NS_COUNT,
+       AAFS_NS_MAX_COUNT,
+       AAFS_NS_SIZE,
+       AAFS_NS_MAX_SIZE,
+       AAFS_NS_OWNER,
+       AAFS_NS_SIZEOF,
+};
+
+enum aafs_prof_type {
+       AAFS_PROF_DIR,
+       AAFS_PROF_PROFS,
+       AAFS_PROF_NAME,
+       AAFS_PROF_MODE,
+       AAFS_PROF_ATTACH,
+       AAFS_PROF_HASH,
+       AAFS_PROF_SIZEOF,
+};
+
+#define ns_dir(X) ((X)->dents[AAFS_NS_DIR])
+#define ns_subns_dir(X) ((X)->dents[AAFS_NS_NS])
+#define ns_subprofs_dir(X) ((X)->dents[AAFS_NS_PROFS])
+
+#define prof_dir(X) ((X)->dents[AAFS_PROF_DIR])
+#define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS])
+
+void __aa_fs_profile_rmdir(struct aa_profile *profile);
+void __aa_fs_profile_migrate_dents(struct aa_profile *old,
+                                  struct aa_profile *new);
+int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent);
+void __aa_fs_namespace_rmdir(struct aa_namespace *ns);
+int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent,
+                           const char *name);
+
 #endif /* __AA_APPARMORFS_H */
index 69d8cae634e7bef79ea136520b404a730914d9d4..30e8d7687259aaef15defab3883e8e1e52d91c1f 100644 (file)
@@ -27,7 +27,6 @@ struct aa_profile;
 
 extern const char *const audit_mode_names[];
 #define AUDIT_MAX_INDEX 5
-
 enum audit_mode {
        AUDIT_NORMAL,           /* follow normal auditing of accesses */
        AUDIT_QUIET_DENIED,     /* quiet all denied access messages */
index c24d2959ea0201eff78244225216df0011b03fc4..2e7c9d6a2f3bb3f7b7ab6f4aab3b63a46a56a10a 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <linux/sched.h>
 
+#include "apparmorfs.h"
+
 struct aa_profile;
 
 /* aa_caps - confinement data for capabilities
@@ -34,6 +36,8 @@ struct aa_caps {
        kernel_cap_t extended;
 };
 
+extern struct aa_fs_entry aa_fs_entry_caps[];
+
 int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
               int audit);
 
index d44ba5802e3dc03f56c6d183a9d97a3d608ee8e9..6bf65798e5d145e985a65f674273db20472ece67 100644 (file)
@@ -98,7 +98,7 @@ static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
 {
        struct aa_task_cxt *cxt = cred_cxt(cred);
        BUG_ON(!cxt || !cxt->profile);
-       return aa_newest_version(cxt->profile);
+       return cxt->profile;
 }
 
 /**
@@ -152,15 +152,14 @@ static inline struct aa_profile *aa_current_profile(void)
        struct aa_profile *profile;
        BUG_ON(!cxt || !cxt->profile);
 
-       profile = aa_newest_version(cxt->profile);
-       /*
-        * Whether or not replacement succeeds, use newest profile so
-        * there is no need to update it after replacement.
-        */
-       if (unlikely((cxt->profile != profile)))
+       if (PROFILE_INVALID(cxt->profile)) {
+               profile = aa_get_newest_profile(cxt->profile);
                aa_replace_current_profile(profile);
+               aa_put_profile(profile);
+               cxt = current_cxt();
+       }
 
-       return profile;
+       return cxt->profile;
 }
 
 /**
diff --git a/security/apparmor/include/crypto.h b/security/apparmor/include/crypto.h
new file mode 100644 (file)
index 0000000..dc418e5
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy loading interface function definitions.
+ *
+ * Copyright 2013 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __APPARMOR_CRYPTO_H
+#define __APPARMOR_CRYPTO_H
+
+#include "policy.h"
+
+#ifdef CONFIG_SECURITY_APPARMOR_HASH
+unsigned int aa_hash_size(void);
+int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
+                        size_t len);
+#else
+static inline int aa_calc_profile_hash(struct aa_profile *profile, u32 version,
+                                      void *start, size_t len)
+{
+       return 0;
+}
+
+static inline unsigned int aa_hash_size(void)
+{
+       return 0;
+}
+#endif
+
+#endif /* __APPARMOR_CRYPTO_H */
index b25491a3046a2a1dd14f16b31828c52d19d5df7e..c28b0f20ab53ed69da7c1e6b8c60a8099370a4f8 100644 (file)
@@ -29,8 +29,8 @@
 #include "file.h"
 #include "resource.h"
 
-extern const char *const profile_mode_names[];
-#define APPARMOR_NAMES_MAX_INDEX 3
+extern const char *const aa_profile_mode_names[];
+#define APPARMOR_MODE_NAMES_MAX_INDEX 4
 
 #define PROFILE_MODE(_profile, _mode)          \
        ((aa_g_profile_mode == (_mode)) ||      \
@@ -42,6 +42,10 @@ extern const char *const profile_mode_names[];
 
 #define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
 
+#define PROFILE_INVALID(_profile) ((_profile)->flags & PFLAG_INVALID)
+
+#define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)
+
 /*
  * FIXME: currently need a clean way to replace and remove profiles as a
  * set.  It should be done at the namespace level.
@@ -52,17 +56,19 @@ enum profile_mode {
        APPARMOR_ENFORCE,       /* enforce access rules */
        APPARMOR_COMPLAIN,      /* allow and log access violations */
        APPARMOR_KILL,          /* kill task on access violation */
+       APPARMOR_UNCONFINED,    /* profile set to unconfined */
 };
 
 enum profile_flags {
        PFLAG_HAT = 1,                  /* profile is a hat */
-       PFLAG_UNCONFINED = 2,           /* profile is an unconfined profile */
        PFLAG_NULL = 4,                 /* profile is null learning profile */
        PFLAG_IX_ON_NAME_ERROR = 8,     /* fallback to ix on name lookup fail */
        PFLAG_IMMUTABLE = 0x10,         /* don't allow changes/replacement */
        PFLAG_USER_DEFINED = 0x20,      /* user based profile - lower privs */
        PFLAG_NO_LIST_REF = 0x40,       /* list doesn't keep profile ref */
        PFLAG_OLD_NULL_TRANS = 0x100,   /* use // as the null transition */
+       PFLAG_INVALID = 0x200,          /* profile replaced/removed */
+       PFLAG_NS_COUNT = 0x400,         /* carries NS ref count */
 
        /* These flags must correspond with PATH_flags */
        PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */
@@ -73,14 +79,12 @@ struct aa_profile;
 /* struct aa_policy - common part of both namespaces and profiles
  * @name: name of the object
  * @hname - The hierarchical name
- * @count: reference count of the obj
  * @list: list policy object is on
  * @profiles: head of the profiles list contained in the object
  */
 struct aa_policy {
        char *name;
        char *hname;
-       struct kref count;
        struct list_head list;
        struct list_head profiles;
 };
@@ -106,6 +110,8 @@ struct aa_ns_acct {
  * @unconfined: special unconfined profile for the namespace
  * @sub_ns: list of namespaces under the current namespace.
  * @uniq_null: uniq value used for null learning profiles
+ * @uniq_id: a unique id count for the profiles in the namespace
+ * @dents: dentries for the namespaces file entries in apparmorfs
  *
  * An aa_namespace defines the set profiles that are searched to determine
  * which profile to attach to a task.  Profiles can not be shared between
@@ -124,11 +130,14 @@ struct aa_ns_acct {
 struct aa_namespace {
        struct aa_policy base;
        struct aa_namespace *parent;
-       rwlock_t lock;
+       struct mutex lock;
        struct aa_ns_acct acct;
        struct aa_profile *unconfined;
        struct list_head sub_ns;
        atomic_t uniq_null;
+       long uniq_id;
+
+       struct dentry *dents[AAFS_NS_SIZEOF];
 };
 
 /* struct aa_policydb - match engine for a policy
@@ -142,12 +151,21 @@ struct aa_policydb {
 
 };
 
+struct aa_replacedby {
+       struct kref count;
+       struct aa_profile __rcu *profile;
+};
+
+
 /* struct aa_profile - basic confinement data
  * @base - base components of the profile (name, refcount, lists, lock ...)
+ * @count: reference count of the obj
+ * @rcu: rcu head used when removing from @list
  * @parent: parent of profile
  * @ns: namespace the profile is in
  * @replacedby: is set to the profile that replaced this profile
  * @rename: optional profile name that this profile renamed
+ * @attach: human readable attachment string
  * @xmatch: optional extended matching for unconfined executables names
  * @xmatch_len: xmatch prefix len, used to determine xmatch priority
  * @audit: the auditing mode of the profile
@@ -160,13 +178,15 @@ struct aa_policydb {
  * @caps: capabilities for the profile
  * @rlimits: rlimits for the profile
  *
+ * @dents: dentries for the profiles file entries in apparmorfs
+ * @dirname: name of the profile dir in apparmorfs
+ *
  * The AppArmor profile contains the basic confinement data.  Each profile
  * has a name, and exists in a namespace.  The @name and @exec_match are
  * used to determine profile attachment against unconfined tasks.  All other
  * attachments are determined by profile X transition rules.
  *
- * The @replacedby field is write protected by the profile lock.  Reads
- * are assumed to be atomic, and are done without locking.
+ * The @replacedby struct is write protected by the profile lock.
  *
  * Profiles have a hierarchy where hats and children profiles keep
  * a reference to their parent.
@@ -177,17 +197,20 @@ struct aa_policydb {
  */
 struct aa_profile {
        struct aa_policy base;
-       struct aa_profile *parent;
+       struct kref count;
+       struct rcu_head rcu;
+       struct aa_profile __rcu *parent;
 
        struct aa_namespace *ns;
-       struct aa_profile *replacedby;
+       struct aa_replacedby *replacedby;
        const char *rename;
 
+       const char *attach;
        struct aa_dfa *xmatch;
        int xmatch_len;
        enum audit_mode audit;
-       enum profile_mode mode;
-       u32 flags;
+       long mode;
+       long flags;
        u32 path_flags;
        int size;
 
@@ -195,6 +218,10 @@ struct aa_profile {
        struct aa_file_rules file;
        struct aa_caps caps;
        struct aa_rlimit rlimits;
+
+       unsigned char *hash;
+       char *dirname;
+       struct dentry *dents[AAFS_PROF_SIZEOF];
 };
 
 extern struct aa_namespace *root_ns;
@@ -211,43 +238,11 @@ void aa_free_namespace_kref(struct kref *kref);
 struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
                                       const char *name);
 
-static inline struct aa_policy *aa_get_common(struct aa_policy *c)
-{
-       if (c)
-               kref_get(&c->count);
-
-       return c;
-}
-
-/**
- * aa_get_namespace - increment references count on @ns
- * @ns: namespace to increment reference count of (MAYBE NULL)
- *
- * Returns: pointer to @ns, if @ns is NULL returns NULL
- * Requires: @ns must be held with valid refcount when called
- */
-static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
-{
-       if (ns)
-               kref_get(&(ns->base.count));
-
-       return ns;
-}
-
-/**
- * aa_put_namespace - decrement refcount on @ns
- * @ns: namespace to put reference of
- *
- * Decrement reference count of @ns and if no longer in use free it
- */
-static inline void aa_put_namespace(struct aa_namespace *ns)
-{
-       if (ns)
-               kref_put(&ns->base.count, aa_free_namespace_kref);
-}
 
+void aa_free_replacedby_kref(struct kref *kref);
 struct aa_profile *aa_alloc_profile(const char *name);
 struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat);
+void aa_free_profile(struct aa_profile *profile);
 void aa_free_profile_kref(struct kref *kref);
 struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
 struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *name);
@@ -259,25 +254,13 @@ ssize_t aa_remove_profiles(char *name, size_t size);
 #define PROF_ADD 1
 #define PROF_REPLACE 0
 
-#define unconfined(X) ((X)->flags & PFLAG_UNCONFINED)
+#define unconfined(X) ((X)->mode == APPARMOR_UNCONFINED)
 
-/**
- * aa_newest_version - find the newest version of @profile
- * @profile: the profile to check for newer versions of (NOT NULL)
- *
- * Returns: newest version of @profile, if @profile is the newest version
- *          return @profile.
- *
- * NOTE: the profile returned is not refcounted, The refcount on @profile
- * must be held until the caller decides what to do with the returned newest
- * version.
- */
-static inline struct aa_profile *aa_newest_version(struct aa_profile *profile)
-{
-       while (profile->replacedby)
-               profile = profile->replacedby;
 
-       return profile;
+static inline struct aa_profile *aa_deref_parent(struct aa_profile *p)
+{
+       return rcu_dereference_protected(p->parent,
+                                        mutex_is_locked(&p->ns->lock));
 }
 
 /**
@@ -290,11 +273,65 @@ static inline struct aa_profile *aa_newest_version(struct aa_profile *profile)
 static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
 {
        if (p)
-               kref_get(&(p->base.count));
+               kref_get(&(p->count));
 
        return p;
 }
 
+/**
+ * aa_get_profile_not0 - increment refcount on profile @p found via lookup
+ * @p: profile  (MAYBE NULL)
+ *
+ * Returns: pointer to @p if @p is NULL will return NULL
+ * Requires: @p must be held with valid refcount when called
+ */
+static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p)
+{
+       if (p && kref_get_not0(&p->count))
+               return p;
+
+       return NULL;
+}
+
+/**
+ * aa_get_profile_rcu - increment a refcount profile that can be replaced
+ * @p: pointer to profile that can be replaced (NOT NULL)
+ *
+ * Returns: pointer to a refcounted profile.
+ *     else NULL if no profile
+ */
+static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p)
+{
+       struct aa_profile *c;
+
+       rcu_read_lock();
+       do {
+               c = rcu_dereference(*p);
+       } while (c && !kref_get_not0(&c->count));
+       rcu_read_unlock();
+
+       return c;
+}
+
+/**
+ * aa_get_newest_profile - find the newest version of @profile
+ * @profile: the profile to check for newer versions of
+ *
+ * Returns: refcounted newest version of @profile taking into account
+ *          replacement, renames and removals
+ *          return @profile.
+ */
+static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
+{
+       if (!p)
+               return NULL;
+
+       if (PROFILE_INVALID(p))
+               return aa_get_profile_rcu(&p->replacedby->profile);
+
+       return aa_get_profile(p);
+}
+
 /**
  * aa_put_profile - decrement refcount on profile @p
  * @p: profile  (MAYBE NULL)
@@ -302,7 +339,60 @@ static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
 static inline void aa_put_profile(struct aa_profile *p)
 {
        if (p)
-               kref_put(&p->base.count, aa_free_profile_kref);
+               kref_put(&p->count, aa_free_profile_kref);
+}
+
+static inline struct aa_replacedby *aa_get_replacedby(struct aa_replacedby *p)
+{
+       if (p)
+               kref_get(&(p->count));
+
+       return p;
+}
+
+static inline void aa_put_replacedby(struct aa_replacedby *p)
+{
+       if (p)
+               kref_put(&p->count, aa_free_replacedby_kref);
+}
+
+/* requires profile list write lock held */
+static inline void __aa_update_replacedby(struct aa_profile *orig,
+                                         struct aa_profile *new)
+{
+       struct aa_profile *tmp;
+       tmp = rcu_dereference_protected(orig->replacedby->profile,
+                                       mutex_is_locked(&orig->ns->lock));
+       rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new));
+       orig->flags |= PFLAG_INVALID;
+       aa_put_profile(tmp);
+}
+
+/**
+ * aa_get_namespace - increment references count on @ns
+ * @ns: namespace to increment reference count of (MAYBE NULL)
+ *
+ * Returns: pointer to @ns, if @ns is NULL returns NULL
+ * Requires: @ns must be held with valid refcount when called
+ */
+static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
+{
+       if (ns)
+               aa_get_profile(ns->unconfined);
+
+       return ns;
+}
+
+/**
+ * aa_put_namespace - decrement refcount on @ns
+ * @ns: namespace to put reference of
+ *
+ * Decrement reference count of @ns and if no longer in use free it
+ */
+static inline void aa_put_namespace(struct aa_namespace *ns)
+{
+       if (ns)
+               aa_put_profile(ns->unconfined);
 }
 
 static inline int AUDIT_MODE(struct aa_profile *profile)
index a2dcccac45aaae960d6a52c65477450e9d70e346..c214fb88b1bc8ada00577d675de1a149f6f30cf8 100644 (file)
 #ifndef __POLICY_INTERFACE_H
 #define __POLICY_INTERFACE_H
 
-struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns);
+#include <linux/list.h>
+
+struct aa_load_ent {
+       struct list_head list;
+       struct aa_profile *new;
+       struct aa_profile *old;
+       struct aa_profile *rename;
+};
+
+void aa_load_ent_free(struct aa_load_ent *ent);
+struct aa_load_ent *aa_load_ent_alloc(void);
+
+#define PACKED_FLAG_HAT                1
+
+#define PACKED_MODE_ENFORCE    0
+#define PACKED_MODE_COMPLAIN   1
+#define PACKED_MODE_KILL       2
+#define PACKED_MODE_UNCONFINED 3
+
+int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns);
 
 #endif /* __POLICY_INTERFACE_H */
index fcfe0233574cb2f32197dcbe84d5170da663d779..69689922c491b8a4eeda5d96115df4a49e6a844f 100644 (file)
@@ -97,11 +97,6 @@ void *__aa_kvmalloc(size_t size, gfp_t flags)
        if (size <= (16*PAGE_SIZE))
                buffer = kmalloc(size, flags | GFP_NOIO | __GFP_NOWARN);
        if (!buffer) {
-               /* see kvfree for why size must be at least work_struct size
-                * when allocated via vmalloc
-                */
-               if (size < sizeof(struct work_struct))
-                       size = sizeof(struct work_struct);
                if (flags & __GFP_ZERO)
                        buffer = vzalloc(size);
                else
index e3a704c75ef68e74b5dadad2be437f8c2b6640d4..fb99e18123b41b4f049fd98078e88aafccb7729b 100644 (file)
@@ -508,19 +508,21 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
        /* released below */
        const struct cred *cred = get_task_cred(task);
        struct aa_task_cxt *cxt = cred_cxt(cred);
+       struct aa_profile *profile = NULL;
 
        if (strcmp(name, "current") == 0)
-               error = aa_getprocattr(aa_newest_version(cxt->profile),
-                                      value);
+               profile = aa_get_newest_profile(cxt->profile);
        else if (strcmp(name, "prev") == 0  && cxt->previous)
-               error = aa_getprocattr(aa_newest_version(cxt->previous),
-                                      value);
+               profile = aa_get_newest_profile(cxt->previous);
        else if (strcmp(name, "exec") == 0 && cxt->onexec)
-               error = aa_getprocattr(aa_newest_version(cxt->onexec),
-                                      value);
+               profile = aa_get_newest_profile(cxt->onexec);
        else
                error = -EINVAL;
 
+       if (profile)
+               error = aa_getprocattr(profile, value);
+
+       aa_put_profile(profile);
        put_cred(cred);
 
        return error;
@@ -744,7 +746,7 @@ module_param_named(paranoid_load, aa_g_paranoid_load, aabool,
 
 /* Boot time disable flag */
 static bool apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
-module_param_named(enabled, apparmor_enabled, aabool, S_IRUSR);
+module_param_named(enabled, apparmor_enabled, bool, S_IRUGO);
 
 static int __init apparmor_enabled_setup(char *str)
 {
@@ -843,7 +845,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp)
        if (!apparmor_enabled)
                return -EINVAL;
 
-       return sprintf(buffer, "%s", profile_mode_names[aa_g_profile_mode]);
+       return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]);
 }
 
 static int param_set_mode(const char *val, struct kernel_param *kp)
@@ -858,8 +860,8 @@ static int param_set_mode(const char *val, struct kernel_param *kp)
        if (!val)
                return -EINVAL;
 
-       for (i = 0; i < APPARMOR_NAMES_MAX_INDEX; i++) {
-               if (strcmp(val, profile_mode_names[i]) == 0) {
+       for (i = 0; i < APPARMOR_MODE_NAMES_MAX_INDEX; i++) {
+               if (strcmp(val, aa_profile_mode_names[i]) == 0) {
                        aa_g_profile_mode = i;
                        return 0;
                }
index 0f345c4dee5f46d7a6bb015d19105a0654a2f7d1..705c2879d3a94a79e10d1190468483c2f9d7192a 100644 (file)
 /* root profile namespace */
 struct aa_namespace *root_ns;
 
-const char *const profile_mode_names[] = {
+const char *const aa_profile_mode_names[] = {
        "enforce",
        "complain",
        "kill",
+       "unconfined",
 };
 
 /**
@@ -141,7 +142,6 @@ static bool policy_init(struct aa_policy *policy, const char *prefix,
        policy->name = (char *)hname_tail(policy->hname);
        INIT_LIST_HEAD(&policy->list);
        INIT_LIST_HEAD(&policy->profiles);
-       kref_init(&policy->count);
 
        return 1;
 }
@@ -153,13 +153,13 @@ static bool policy_init(struct aa_policy *policy, const char *prefix,
 static void policy_destroy(struct aa_policy *policy)
 {
        /* still contains profiles -- invalid */
-       if (!list_empty(&policy->profiles)) {
+       if (on_list_rcu(&policy->profiles)) {
                AA_ERROR("%s: internal error, "
                         "policy '%s' still contains profiles\n",
                         __func__, policy->name);
                BUG();
        }
-       if (!list_empty(&policy->list)) {
+       if (on_list_rcu(&policy->list)) {
                AA_ERROR("%s: internal error, policy '%s' still on list\n",
                         __func__, policy->name);
                BUG();
@@ -174,7 +174,7 @@ static void policy_destroy(struct aa_policy *policy)
  * @head: list to search  (NOT NULL)
  * @name: name to search for  (NOT NULL)
  *
- * Requires: correct locks for the @head list be held
+ * Requires: rcu_read_lock be held
  *
  * Returns: unrefcounted policy that match @name or NULL if not found
  */
@@ -182,7 +182,7 @@ static struct aa_policy *__policy_find(struct list_head *head, const char *name)
 {
        struct aa_policy *policy;
 
-       list_for_each_entry(policy, head, list) {
+       list_for_each_entry_rcu(policy, head, list) {
                if (!strcmp(policy->name, name))
                        return policy;
        }
@@ -195,7 +195,7 @@ static struct aa_policy *__policy_find(struct list_head *head, const char *name)
  * @str: string to search for  (NOT NULL)
  * @len: length of match required
  *
- * Requires: correct locks for the @head list be held
+ * Requires: rcu_read_lock be held
  *
  * Returns: unrefcounted policy that match @str or NULL if not found
  *
@@ -207,7 +207,7 @@ static struct aa_policy *__policy_strn_find(struct list_head *head,
 {
        struct aa_policy *policy;
 
-       list_for_each_entry(policy, head, list) {
+       list_for_each_entry_rcu(policy, head, list) {
                if (aa_strneq(policy->name, str, len))
                        return policy;
        }
@@ -284,22 +284,19 @@ static struct aa_namespace *alloc_namespace(const char *prefix,
                goto fail_ns;
 
        INIT_LIST_HEAD(&ns->sub_ns);
-       rwlock_init(&ns->lock);
+       mutex_init(&ns->lock);
 
        /* released by free_namespace */
        ns->unconfined = aa_alloc_profile("unconfined");
        if (!ns->unconfined)
                goto fail_unconfined;
 
-       ns->unconfined->flags = PFLAG_UNCONFINED | PFLAG_IX_ON_NAME_ERROR |
-           PFLAG_IMMUTABLE;
+       ns->unconfined->flags = PFLAG_IX_ON_NAME_ERROR |
+               PFLAG_IMMUTABLE | PFLAG_NS_COUNT;
+       ns->unconfined->mode = APPARMOR_UNCONFINED;
 
-       /*
-        * released by free_namespace, however __remove_namespace breaks
-        * the cyclic references (ns->unconfined, and unconfined->ns) and
-        * replaces with refs to parent namespace unconfined
-        */
-       ns->unconfined->ns = aa_get_namespace(ns);
+       /* ns and ns->unconfined share ns->unconfined refcount */
+       ns->unconfined->ns = ns;
 
        atomic_set(&ns->uniq_null, 0);
 
@@ -327,22 +324,11 @@ static void free_namespace(struct aa_namespace *ns)
        policy_destroy(&ns->base);
        aa_put_namespace(ns->parent);
 
-       if (ns->unconfined && ns->unconfined->ns == ns)
-               ns->unconfined->ns = NULL;
-
-       aa_put_profile(ns->unconfined);
+       ns->unconfined->ns = NULL;
+       aa_free_profile(ns->unconfined);
        kzfree(ns);
 }
 
-/**
- * aa_free_namespace_kref - free aa_namespace by kref (see aa_put_namespace)
- * @kr: kref callback for freeing of a namespace  (NOT NULL)
- */
-void aa_free_namespace_kref(struct kref *kref)
-{
-       free_namespace(container_of(kref, struct aa_namespace, base.count));
-}
-
 /**
  * __aa_find_namespace - find a namespace on a list by @name
  * @head: list to search for namespace on  (NOT NULL)
@@ -350,7 +336,7 @@ void aa_free_namespace_kref(struct kref *kref)
  *
  * Returns: unrefcounted namespace
  *
- * Requires: ns lock be held
+ * Requires: rcu_read_lock be held
  */
 static struct aa_namespace *__aa_find_namespace(struct list_head *head,
                                                const char *name)
@@ -373,9 +359,9 @@ struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
 {
        struct aa_namespace *ns = NULL;
 
-       read_lock(&root->lock);
+       rcu_read_lock();
        ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name));
-       read_unlock(&root->lock);
+       rcu_read_unlock();
 
        return ns;
 }
@@ -392,7 +378,7 @@ static struct aa_namespace *aa_prepare_namespace(const char *name)
 
        root = aa_current_profile()->ns;
 
-       write_lock(&root->lock);
+       mutex_lock(&root->lock);
 
        /* if name isn't specified the profile is loaded to the current ns */
        if (!name) {
@@ -405,31 +391,23 @@ static struct aa_namespace *aa_prepare_namespace(const char *name)
        /* released by caller */
        ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name));
        if (!ns) {
-               /* namespace not found */
-               struct aa_namespace *new_ns;
-               write_unlock(&root->lock);
-               new_ns = alloc_namespace(root->base.hname, name);
-               if (!new_ns)
-                       return NULL;
-               write_lock(&root->lock);
-               /* test for race when new_ns was allocated */
-               ns = __aa_find_namespace(&root->sub_ns, name);
-               if (!ns) {
-                       /* add parent ref */
-                       new_ns->parent = aa_get_namespace(root);
-
-                       list_add(&new_ns->base.list, &root->sub_ns);
-                       /* add list ref */
-                       ns = aa_get_namespace(new_ns);
-               } else {
-                       /* raced so free the new one */
-                       free_namespace(new_ns);
-                       /* get reference on namespace */
-                       aa_get_namespace(ns);
+               ns = alloc_namespace(root->base.hname, name);
+               if (!ns)
+                       goto out;
+               if (__aa_fs_namespace_mkdir(ns, ns_subns_dir(root), name)) {
+                       AA_ERROR("Failed to create interface for ns %s\n",
+                                ns->base.name);
+                       free_namespace(ns);
+                       ns = NULL;
+                       goto out;
                }
+               ns->parent = aa_get_namespace(root);
+               list_add_rcu(&ns->base.list, &root->sub_ns);
+               /* add list ref */
+               aa_get_namespace(ns);
        }
 out:
-       write_unlock(&root->lock);
+       mutex_unlock(&root->lock);
 
        /* return ref */
        return ns;
@@ -447,7 +425,7 @@ out:
 static void __list_add_profile(struct list_head *list,
                               struct aa_profile *profile)
 {
-       list_add(&profile->base.list, list);
+       list_add_rcu(&profile->base.list, list);
        /* get list reference */
        aa_get_profile(profile);
 }
@@ -466,49 +444,8 @@ static void __list_add_profile(struct list_head *list,
  */
 static void __list_remove_profile(struct aa_profile *profile)
 {
-       list_del_init(&profile->base.list);
-       if (!(profile->flags & PFLAG_NO_LIST_REF))
-               /* release list reference */
-               aa_put_profile(profile);
-}
-
-/**
- * __replace_profile - replace @old with @new on a list
- * @old: profile to be replaced  (NOT NULL)
- * @new: profile to replace @old with  (NOT NULL)
- *
- * Will duplicate and refcount elements that @new inherits from @old
- * and will inherit @old children.
- *
- * refcount @new for list, put @old list refcount
- *
- * Requires: namespace list lock be held, or list not be shared
- */
-static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
-{
-       struct aa_policy *policy;
-       struct aa_profile *child, *tmp;
-
-       if (old->parent)
-               policy = &old->parent->base;
-       else
-               policy = &old->ns->base;
-
-       /* released when @new is freed */
-       new->parent = aa_get_profile(old->parent);
-       new->ns = aa_get_namespace(old->ns);
-       __list_add_profile(&policy->profiles, new);
-       /* inherit children */
-       list_for_each_entry_safe(child, tmp, &old->base.profiles, base.list) {
-               aa_put_profile(child->parent);
-               child->parent = aa_get_profile(new);
-               /* list refcount transferred to @new*/
-               list_move(&child->base.list, &new->base.profiles);
-       }
-
-       /* released by free_profile */
-       old->replacedby = aa_get_profile(new);
-       __list_remove_profile(old);
+       list_del_rcu(&profile->base.list);
+       aa_put_profile(profile);
 }
 
 static void __profile_list_release(struct list_head *head);
@@ -524,7 +461,8 @@ static void __remove_profile(struct aa_profile *profile)
        /* release any children lists first */
        __profile_list_release(&profile->base.profiles);
        /* released by free_profile */
-       profile->replacedby = aa_get_profile(profile->ns->unconfined);
+       __aa_update_replacedby(profile, profile->ns->unconfined);
+       __aa_fs_profile_rmdir(profile);
        __list_remove_profile(profile);
 }
 
@@ -552,14 +490,17 @@ static void destroy_namespace(struct aa_namespace *ns)
        if (!ns)
                return;
 
-       write_lock(&ns->lock);
+       mutex_lock(&ns->lock);
        /* release all profiles in this namespace */
        __profile_list_release(&ns->base.profiles);
 
        /* release all sub namespaces */
        __ns_list_release(&ns->sub_ns);
 
-       write_unlock(&ns->lock);
+       if (ns->parent)
+               __aa_update_replacedby(ns->unconfined, ns->parent->unconfined);
+       __aa_fs_namespace_rmdir(ns);
+       mutex_unlock(&ns->lock);
 }
 
 /**
@@ -570,25 +511,9 @@ static void destroy_namespace(struct aa_namespace *ns)
  */
 static void __remove_namespace(struct aa_namespace *ns)
 {
-       struct aa_profile *unconfined = ns->unconfined;
-
        /* remove ns from namespace list */
-       list_del_init(&ns->base.list);
-
-       /*
-        * break the ns, unconfined profile cyclic reference and forward
-        * all new unconfined profiles requests to the parent namespace
-        * This will result in all confined tasks that have a profile
-        * being removed, inheriting the parent->unconfined profile.
-        */
-       if (ns->parent)
-               ns->unconfined = aa_get_profile(ns->parent->unconfined);
-
+       list_del_rcu(&ns->base.list);
        destroy_namespace(ns);
-
-       /* release original ns->unconfined ref */
-       aa_put_profile(unconfined);
-       /* release ns->base.list ref, from removal above */
        aa_put_namespace(ns);
 }
 
@@ -634,8 +559,26 @@ void __init aa_free_root_ns(void)
         aa_put_namespace(ns);
 }
 
+
+static void free_replacedby(struct aa_replacedby *r)
+{
+       if (r) {
+               /* r->profile will not be updated any more as r is dead */
+               aa_put_profile(rcu_dereference_protected(r->profile, true));
+               kzfree(r);
+       }
+}
+
+
+void aa_free_replacedby_kref(struct kref *kref)
+{
+       struct aa_replacedby *r = container_of(kref, struct aa_replacedby,
+                                              count);
+       free_replacedby(r);
+}
+
 /**
- * free_profile - free a profile
+ * aa_free_profile - free a profile
  * @profile: the profile to free  (MAYBE NULL)
  *
  * Free a profile, its hats and null_profile. All references to the profile,
@@ -644,25 +587,16 @@ void __init aa_free_root_ns(void)
  * If the profile was referenced from a task context, free_profile() will
  * be called from an rcu callback routine, so we must not sleep here.
  */
-static void free_profile(struct aa_profile *profile)
+void aa_free_profile(struct aa_profile *profile)
 {
-       struct aa_profile *p;
-
        AA_DEBUG("%s(%p)\n", __func__, profile);
 
        if (!profile)
                return;
 
-       if (!list_empty(&profile->base.list)) {
-               AA_ERROR("%s: internal error, "
-                        "profile '%s' still on ns list\n",
-                        __func__, profile->base.name);
-               BUG();
-       }
-
        /* free children profiles */
        policy_destroy(&profile->base);
-       aa_put_profile(profile->parent);
+       aa_put_profile(rcu_access_pointer(profile->parent));
 
        aa_put_namespace(profile->ns);
        kzfree(profile->rename);
@@ -671,44 +605,36 @@ static void free_profile(struct aa_profile *profile)
        aa_free_cap_rules(&profile->caps);
        aa_free_rlimit_rules(&profile->rlimits);
 
+       kzfree(profile->dirname);
        aa_put_dfa(profile->xmatch);
        aa_put_dfa(profile->policy.dfa);
+       aa_put_replacedby(profile->replacedby);
 
-       /* put the profile reference for replacedby, but not via
-        * put_profile(kref_put).
-        * replacedby can form a long chain that can result in cascading
-        * frees that blows the stack because kref_put makes a nested fn
-        * call (it looks like recursion, with free_profile calling
-        * free_profile) for each profile in the chain lp#1056078.
-        */
-       for (p = profile->replacedby; p; ) {
-               if (atomic_dec_and_test(&p->base.count.refcount)) {
-                       /* no more refs on p, grab its replacedby */
-                       struct aa_profile *next = p->replacedby;
-                       /* break the chain */
-                       p->replacedby = NULL;
-                       /* now free p, chain is broken */
-                       free_profile(p);
-
-                       /* follow up with next profile in the chain */
-                       p = next;
-               } else
-                       break;
-       }
-
+       kzfree(profile->hash);
        kzfree(profile);
 }
 
+/**
+ * aa_free_profile_rcu - free aa_profile by rcu (called by aa_free_profile_kref)
+ * @head: rcu_head callback for freeing of a profile  (NOT NULL)
+ */
+static void aa_free_profile_rcu(struct rcu_head *head)
+{
+       struct aa_profile *p = container_of(head, struct aa_profile, rcu);
+       if (p->flags & PFLAG_NS_COUNT)
+               free_namespace(p->ns);
+       else
+               aa_free_profile(p);
+}
+
 /**
  * aa_free_profile_kref - free aa_profile by kref (called by aa_put_profile)
  * @kr: kref callback for freeing of a profile  (NOT NULL)
  */
 void aa_free_profile_kref(struct kref *kref)
 {
-       struct aa_profile *p = container_of(kref, struct aa_profile,
-                                           base.count);
-
-       free_profile(p);
+       struct aa_profile *p = container_of(kref, struct aa_profile, count);
+       call_rcu(&p->rcu, aa_free_profile_rcu);
 }
 
 /**
@@ -726,13 +652,23 @@ struct aa_profile *aa_alloc_profile(const char *hname)
        if (!profile)
                return NULL;
 
-       if (!policy_init(&profile->base, NULL, hname)) {
-               kzfree(profile);
-               return NULL;
-       }
+       profile->replacedby = kzalloc(sizeof(struct aa_replacedby), GFP_KERNEL);
+       if (!profile->replacedby)
+               goto fail;
+       kref_init(&profile->replacedby->count);
+
+       if (!policy_init(&profile->base, NULL, hname))
+               goto fail;
+       kref_init(&profile->count);
 
        /* refcount released by caller */
        return profile;
+
+fail:
+       kzfree(profile->replacedby);
+       kzfree(profile);
+
+       return NULL;
 }
 
 /**
@@ -772,12 +708,12 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
                profile->flags |= PFLAG_HAT;
 
        /* released on free_profile */
-       profile->parent = aa_get_profile(parent);
+       rcu_assign_pointer(profile->parent, aa_get_profile(parent));
        profile->ns = aa_get_namespace(parent->ns);
 
-       write_lock(&profile->ns->lock);
+       mutex_lock(&profile->ns->lock);
        __list_add_profile(&parent->base.profiles, profile);
-       write_unlock(&profile->ns->lock);
+       mutex_unlock(&profile->ns->lock);
 
        /* refcount released by caller */
        return profile;
@@ -793,7 +729,7 @@ fail:
  * @head: list to search  (NOT NULL)
  * @name: name of profile (NOT NULL)
  *
- * Requires: ns lock protecting list be held
+ * Requires: rcu_read_lock be held
  *
  * Returns: unrefcounted profile ptr, or NULL if not found
  */
@@ -808,7 +744,7 @@ static struct aa_profile *__find_child(struct list_head *head, const char *name)
  * @name: name of profile (NOT NULL)
  * @len: length of @name substring to match
  *
- * Requires: ns lock protecting list be held
+ * Requires: rcu_read_lock be held
  *
  * Returns: unrefcounted profile ptr, or NULL if not found
  */
@@ -829,9 +765,9 @@ struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name)
 {
        struct aa_profile *profile;
 
-       read_lock(&parent->ns->lock);
+       rcu_read_lock();
        profile = aa_get_profile(__find_child(&parent->base.profiles, name));
-       read_unlock(&parent->ns->lock);
+       rcu_read_unlock();
 
        /* refcount released by caller */
        return profile;
@@ -846,7 +782,7 @@ struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name)
  * that matches hname does not need to exist, in general this
  * is used to load a new profile.
  *
- * Requires: ns->lock be held
+ * Requires: rcu_read_lock be held
  *
  * Returns: unrefcounted policy or NULL if not found
  */
@@ -878,7 +814,7 @@ static struct aa_policy *__lookup_parent(struct aa_namespace *ns,
  * @base: base list to start looking up profile name from  (NOT NULL)
  * @hname: hierarchical profile name  (NOT NULL)
  *
- * Requires: ns->lock be held
+ * Requires: rcu_read_lock be held
  *
  * Returns: unrefcounted profile pointer or NULL if not found
  *
@@ -917,13 +853,15 @@ struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname)
 {
        struct aa_profile *profile;
 
-       read_lock(&ns->lock);
-       profile = aa_get_profile(__lookup_profile(&ns->base, hname));
-       read_unlock(&ns->lock);
+       rcu_read_lock();
+       do {
+               profile = __lookup_profile(&ns->base, hname);
+       } while (profile && !aa_get_profile_not0(profile));
+       rcu_read_unlock();
 
        /* the unconfined profile is not in the regular profile list */
        if (!profile && strcmp(hname, "unconfined") == 0)
-               profile = aa_get_profile(ns->unconfined);
+               profile = aa_get_newest_profile(ns->unconfined);
 
        /* refcount released by caller */
        return profile;
@@ -952,25 +890,6 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace,
        return 0;
 }
 
-/**
- * __add_new_profile - simple wrapper around __list_add_profile
- * @ns: namespace that profile is being added to  (NOT NULL)
- * @policy: the policy container to add the profile to  (NOT NULL)
- * @profile: profile to add  (NOT NULL)
- *
- * add a profile to a list and do other required basic allocations
- */
-static void __add_new_profile(struct aa_namespace *ns, struct aa_policy *policy,
-                             struct aa_profile *profile)
-{
-       if (policy != &ns->base)
-               /* released on profile replacement or free_profile */
-               profile->parent = aa_get_profile((struct aa_profile *) policy);
-       __list_add_profile(&policy->profiles, profile);
-       /* released on free_profile */
-       profile->ns = aa_get_namespace(ns);
-}
-
 /**
  * aa_audit_policy - Do auditing of policy changes
  * @op: policy operation being performed
@@ -1019,6 +938,121 @@ bool aa_may_manage_policy(int op)
        return 1;
 }
 
+static struct aa_profile *__list_lookup_parent(struct list_head *lh,
+                                              struct aa_profile *profile)
+{
+       const char *base = hname_tail(profile->base.hname);
+       long len = base - profile->base.hname;
+       struct aa_load_ent *ent;
+
+       /* parent won't have trailing // so remove from len */
+       if (len <= 2)
+               return NULL;
+       len -= 2;
+
+       list_for_each_entry(ent, lh, list) {
+               if (ent->new == profile)
+                       continue;
+               if (strncmp(ent->new->base.hname, profile->base.hname, len) ==
+                   0 && ent->new->base.hname[len] == 0)
+                       return ent->new;
+       }
+
+       return NULL;
+}
+
+/**
+ * __replace_profile - replace @old with @new on a list
+ * @old: profile to be replaced  (NOT NULL)
+ * @new: profile to replace @old with  (NOT NULL)
+ * @share_replacedby: transfer @old->replacedby to @new
+ *
+ * Will duplicate and refcount elements that @new inherits from @old
+ * and will inherit @old children.
+ *
+ * refcount @new for list, put @old list refcount
+ *
+ * Requires: namespace list lock be held, or list not be shared
+ */
+static void __replace_profile(struct aa_profile *old, struct aa_profile *new,
+                             bool share_replacedby)
+{
+       struct aa_profile *child, *tmp;
+
+       if (!list_empty(&old->base.profiles)) {
+               LIST_HEAD(lh);
+               list_splice_init_rcu(&old->base.profiles, &lh, synchronize_rcu);
+
+               list_for_each_entry_safe(child, tmp, &lh, base.list) {
+                       struct aa_profile *p;
+
+                       list_del_init(&child->base.list);
+                       p = __find_child(&new->base.profiles, child->base.name);
+                       if (p) {
+                               /* @p replaces @child  */
+                               __replace_profile(child, p, share_replacedby);
+                               continue;
+                       }
+
+                       /* inherit @child and its children */
+                       /* TODO: update hname of inherited children */
+                       /* list refcount transferred to @new */
+                       p = aa_deref_parent(child);
+                       rcu_assign_pointer(child->parent, aa_get_profile(new));
+                       list_add_rcu(&child->base.list, &new->base.profiles);
+                       aa_put_profile(p);
+               }
+       }
+
+       if (!rcu_access_pointer(new->parent)) {
+               struct aa_profile *parent = aa_deref_parent(old);
+               rcu_assign_pointer(new->parent, aa_get_profile(parent));
+       }
+       __aa_update_replacedby(old, new);
+       if (share_replacedby) {
+               aa_put_replacedby(new->replacedby);
+               new->replacedby = aa_get_replacedby(old->replacedby);
+       } else if (!rcu_access_pointer(new->replacedby->profile))
+               /* aafs interface uses replacedby */
+               rcu_assign_pointer(new->replacedby->profile,
+                                  aa_get_profile(new));
+       __aa_fs_profile_migrate_dents(old, new);
+
+       if (list_empty(&new->base.list)) {
+               /* new is not on a list already */
+               list_replace_rcu(&old->base.list, &new->base.list);
+               aa_get_profile(new);
+               aa_put_profile(old);
+       } else
+               __list_remove_profile(old);
+}
+
+/**
+ * __lookup_replace - lookup replacement information for a profile
+ * @ns - namespace the lookup occurs in
+ * @hname - name of profile to lookup
+ * @noreplace - true if not replacing an existing profile
+ * @p - Returns: profile to be replaced
+ * @info - Returns: info string on why lookup failed
+ *
+ * Returns: profile to replace (no ref) on success else ptr error
+ */
+static int __lookup_replace(struct aa_namespace *ns, const char *hname,
+                           bool noreplace, struct aa_profile **p,
+                           const char **info)
+{
+       *p = aa_get_profile(__lookup_profile(&ns->base, hname));
+       if (*p) {
+               int error = replacement_allowed(*p, noreplace, info);
+               if (error) {
+                       *info = "profile can not be replaced";
+                       return error;
+               }
+       }
+
+       return 0;
+}
+
 /**
  * aa_replace_profiles - replace profile(s) on the profile list
  * @udata: serialized data stream  (NOT NULL)
@@ -1033,21 +1067,17 @@ bool aa_may_manage_policy(int op)
  */
 ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
 {
-       struct aa_policy *policy;
-       struct aa_profile *old_profile = NULL, *new_profile = NULL;
-       struct aa_profile *rename_profile = NULL;
-       struct aa_namespace *ns = NULL;
        const char *ns_name, *name = NULL, *info = NULL;
+       struct aa_namespace *ns = NULL;
+       struct aa_load_ent *ent, *tmp;
        int op = OP_PROF_REPL;
        ssize_t error;
+       LIST_HEAD(lh);
 
        /* released below */
-       new_profile = aa_unpack(udata, size, &ns_name);
-       if (IS_ERR(new_profile)) {
-               error = PTR_ERR(new_profile);
-               new_profile = NULL;
-               goto fail;
-       }
+       error = aa_unpack(udata, size, &lh, &ns_name);
+       if (error)
+               goto out;
 
        /* released below */
        ns = aa_prepare_namespace(ns_name);
@@ -1058,71 +1088,140 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
                goto fail;
        }
 
-       name = new_profile->base.hname;
-
-       write_lock(&ns->lock);
-       /* no ref on policy only use inside lock */
-       policy = __lookup_parent(ns, new_profile->base.hname);
+       mutex_lock(&ns->lock);
+       /* setup parent and ns info */
+       list_for_each_entry(ent, &lh, list) {
+               struct aa_policy *policy;
+
+               name = ent->new->base.hname;
+               error = __lookup_replace(ns, ent->new->base.hname, noreplace,
+                                        &ent->old, &info);
+               if (error)
+                       goto fail_lock;
+
+               if (ent->new->rename) {
+                       error = __lookup_replace(ns, ent->new->rename,
+                                                noreplace, &ent->rename,
+                                                &info);
+                       if (error)
+                               goto fail_lock;
+               }
 
-       if (!policy) {
-               info = "parent does not exist";
-               error = -ENOENT;
-               goto audit;
+               /* released when @new is freed */
+               ent->new->ns = aa_get_namespace(ns);
+
+               if (ent->old || ent->rename)
+                       continue;
+
+               /* no ref on policy only use inside lock */
+               policy = __lookup_parent(ns, ent->new->base.hname);
+               if (!policy) {
+                       struct aa_profile *p;
+                       p = __list_lookup_parent(&lh, ent->new);
+                       if (!p) {
+                               error = -ENOENT;
+                               info = "parent does not exist";
+                               name = ent->new->base.hname;
+                               goto fail_lock;
+                       }
+                       rcu_assign_pointer(ent->new->parent, aa_get_profile(p));
+               } else if (policy != &ns->base) {
+                       /* released on profile replacement or free_profile */
+                       struct aa_profile *p = (struct aa_profile *) policy;
+                       rcu_assign_pointer(ent->new->parent, aa_get_profile(p));
+               }
        }
 
-       old_profile = __find_child(&policy->profiles, new_profile->base.name);
-       /* released below */
-       aa_get_profile(old_profile);
+       /* create new fs entries for introspection if needed */
+       list_for_each_entry(ent, &lh, list) {
+               if (ent->old) {
+                       /* inherit old interface files */
 
-       if (new_profile->rename) {
-               rename_profile = __lookup_profile(&ns->base,
-                                                 new_profile->rename);
-               /* released below */
-               aa_get_profile(rename_profile);
+                       /* if (ent->rename)
+                               TODO: support rename */
+               /* } else if (ent->rename) {
+                       TODO: support rename */
+               } else {
+                       struct dentry *parent;
+                       if (rcu_access_pointer(ent->new->parent)) {
+                               struct aa_profile *p;
+                               p = aa_deref_parent(ent->new);
+                               parent = prof_child_dir(p);
+                       } else
+                               parent = ns_subprofs_dir(ent->new->ns);
+                       error = __aa_fs_profile_mkdir(ent->new, parent);
+               }
 
-               if (!rename_profile) {
-                       info = "profile to rename does not exist";
-                       name = new_profile->rename;
-                       error = -ENOENT;
-                       goto audit;
+               if (error) {
+                       info = "failed to create ";
+                       goto fail_lock;
                }
        }
 
-       error = replacement_allowed(old_profile, noreplace, &info);
-       if (error)
-               goto audit;
-
-       error = replacement_allowed(rename_profile, noreplace, &info);
-       if (error)
-               goto audit;
-
-audit:
-       if (!old_profile && !rename_profile)
-               op = OP_PROF_LOAD;
-
-       error = audit_policy(op, GFP_ATOMIC, name, info, error);
-
-       if (!error) {
-               if (rename_profile)
-                       __replace_profile(rename_profile, new_profile);
-               if (old_profile)
-                       __replace_profile(old_profile, new_profile);
-               if (!(old_profile || rename_profile))
-                       __add_new_profile(ns, policy, new_profile);
+       /* Done with checks that may fail - do actual replacement */
+       list_for_each_entry_safe(ent, tmp, &lh, list) {
+               list_del_init(&ent->list);
+               op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL;
+
+               audit_policy(op, GFP_ATOMIC, ent->new->base.name, NULL, error);
+
+               if (ent->old) {
+                       __replace_profile(ent->old, ent->new, 1);
+                       if (ent->rename) {
+                               /* aafs interface uses replacedby */
+                               struct aa_replacedby *r = ent->new->replacedby;
+                               rcu_assign_pointer(r->profile,
+                                                  aa_get_profile(ent->new));
+                               __replace_profile(ent->rename, ent->new, 0);
+                       }
+               } else if (ent->rename) {
+                       /* aafs interface uses replacedby */
+                       rcu_assign_pointer(ent->new->replacedby->profile,
+                                          aa_get_profile(ent->new));
+                       __replace_profile(ent->rename, ent->new, 0);
+               } else if (ent->new->parent) {
+                       struct aa_profile *parent, *newest;
+                       parent = aa_deref_parent(ent->new);
+                       newest = aa_get_newest_profile(parent);
+
+                       /* parent replaced in this atomic set? */
+                       if (newest != parent) {
+                               aa_get_profile(newest);
+                               aa_put_profile(parent);
+                               rcu_assign_pointer(ent->new->parent, newest);
+                       } else
+                               aa_put_profile(newest);
+                       /* aafs interface uses replacedby */
+                       rcu_assign_pointer(ent->new->replacedby->profile,
+                                          aa_get_profile(ent->new));
+                       __list_add_profile(&parent->base.profiles, ent->new);
+               } else {
+                       /* aafs interface uses replacedby */
+                       rcu_assign_pointer(ent->new->replacedby->profile,
+                                          aa_get_profile(ent->new));
+                       __list_add_profile(&ns->base.profiles, ent->new);
+               }
+               aa_load_ent_free(ent);
        }
-       write_unlock(&ns->lock);
+       mutex_unlock(&ns->lock);
 
 out:
        aa_put_namespace(ns);
-       aa_put_profile(rename_profile);
-       aa_put_profile(old_profile);
-       aa_put_profile(new_profile);
+
        if (error)
                return error;
        return size;
 
+fail_lock:
+       mutex_unlock(&ns->lock);
 fail:
        error = audit_policy(op, GFP_KERNEL, name, info, error);
+
+       list_for_each_entry_safe(ent, tmp, &lh, list) {
+               list_del_init(&ent->list);
+               aa_load_ent_free(ent);
+       }
+
        goto out;
 }
 
@@ -1169,12 +1268,12 @@ ssize_t aa_remove_profiles(char *fqname, size_t size)
 
        if (!name) {
                /* remove namespace - can only happen if fqname[0] == ':' */
-               write_lock(&ns->parent->lock);
+               mutex_lock(&ns->parent->lock);
                __remove_namespace(ns);
-               write_unlock(&ns->parent->lock);
+               mutex_unlock(&ns->parent->lock);
        } else {
                /* remove profile */
-               write_lock(&ns->lock);
+               mutex_lock(&ns->lock);
                profile = aa_get_profile(__lookup_profile(&ns->base, name));
                if (!profile) {
                        error = -ENOENT;
@@ -1183,7 +1282,7 @@ ssize_t aa_remove_profiles(char *fqname, size_t size)
                }
                name = profile->base.hname;
                __remove_profile(profile);
-               write_unlock(&ns->lock);
+               mutex_unlock(&ns->lock);
        }
 
        /* don't fail removal if audit fails */
@@ -1193,7 +1292,7 @@ ssize_t aa_remove_profiles(char *fqname, size_t size)
        return size;
 
 fail_ns_lock:
-       write_unlock(&ns->lock);
+       mutex_unlock(&ns->lock);
        aa_put_namespace(ns);
 
 fail:
index 6dac7d77cb4d53c1241402d7a267466c31dbb613..a689f10930b5e825c4da751508e274d8715ef2b5 100644 (file)
@@ -24,6 +24,7 @@
 #include "include/apparmor.h"
 #include "include/audit.h"
 #include "include/context.h"
+#include "include/crypto.h"
 #include "include/match.h"
 #include "include/policy.h"
 #include "include/policy_unpack.h"
@@ -333,8 +334,10 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e)
                /*
                 * The dfa is aligned with in the blob to 8 bytes
                 * from the beginning of the stream.
+                * alignment adjust needed by dfa unpack
                 */
-               size_t sz = blob - (char *)e->start;
+               size_t sz = blob - (char *) e->start -
+                       ((e->pos - e->start) & 7);
                size_t pad = ALIGN(sz, 8) - sz;
                int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
                        TO_ACCEPT2_FLAG(YYTD_DATA32);
@@ -490,6 +493,9 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
        /* profile renaming is optional */
        (void) unpack_str(e, &profile->rename, "rename");
 
+       /* attachment string is optional */
+       (void) unpack_str(e, &profile->attach, "attach");
+
        /* xmatch is optional and may be NULL */
        profile->xmatch = unpack_dfa(e);
        if (IS_ERR(profile->xmatch)) {
@@ -509,12 +515,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
                goto fail;
        if (!unpack_u32(e, &tmp, NULL))
                goto fail;
-       if (tmp)
+       if (tmp & PACKED_FLAG_HAT)
                profile->flags |= PFLAG_HAT;
        if (!unpack_u32(e, &tmp, NULL))
                goto fail;
-       if (tmp)
+       if (tmp == PACKED_MODE_COMPLAIN)
                profile->mode = APPARMOR_COMPLAIN;
+       else if (tmp == PACKED_MODE_KILL)
+               profile->mode = APPARMOR_KILL;
+       else if (tmp == PACKED_MODE_UNCONFINED)
+               profile->mode = APPARMOR_UNCONFINED;
        if (!unpack_u32(e, &tmp, NULL))
                goto fail;
        if (tmp)
@@ -614,7 +624,7 @@ fail:
        else if (!name)
                name = "unknown";
        audit_iface(profile, name, "failed to unpack profile", e, error);
-       aa_put_profile(profile);
+       aa_free_profile(profile);
 
        return ERR_PTR(error);
 }
@@ -622,29 +632,41 @@ fail:
 /**
  * verify_head - unpack serialized stream header
  * @e: serialized data read head (NOT NULL)
+ * @required: whether the header is required or optional
  * @ns: Returns - namespace if one is specified else NULL (NOT NULL)
  *
  * Returns: error or 0 if header is good
  */
-static int verify_header(struct aa_ext *e, const char **ns)
+static int verify_header(struct aa_ext *e, int required, const char **ns)
 {
        int error = -EPROTONOSUPPORT;
+       const char *name = NULL;
+       *ns = NULL;
+
        /* get the interface version */
        if (!unpack_u32(e, &e->version, "version")) {
-               audit_iface(NULL, NULL, "invalid profile format", e, error);
-               return error;
-       }
+               if (required) {
+                       audit_iface(NULL, NULL, "invalid profile format", e,
+                                   error);
+                       return error;
+               }
 
-       /* check that the interface version is currently supported */
-       if (e->version != 5) {
-               audit_iface(NULL, NULL, "unsupported interface version", e,
-                           error);
-               return error;
+               /* check that the interface version is currently supported */
+               if (e->version != 5) {
+                       audit_iface(NULL, NULL, "unsupported interface version",
+                                   e, error);
+                       return error;
+               }
        }
 
+
        /* read the namespace if present */
-       if (!unpack_str(e, ns, "namespace"))
-               *ns = NULL;
+       if (unpack_str(e, &name, "namespace")) {
+               if (*ns && strcmp(*ns, name))
+                       audit_iface(NULL, NULL, "invalid ns change", e, error);
+               else if (!*ns)
+                       *ns = name;
+       }
 
        return 0;
 }
@@ -693,18 +715,40 @@ static int verify_profile(struct aa_profile *profile)
        return 0;
 }
 
+void aa_load_ent_free(struct aa_load_ent *ent)
+{
+       if (ent) {
+               aa_put_profile(ent->rename);
+               aa_put_profile(ent->old);
+               aa_put_profile(ent->new);
+               kzfree(ent);
+       }
+}
+
+struct aa_load_ent *aa_load_ent_alloc(void)
+{
+       struct aa_load_ent *ent = kzalloc(sizeof(*ent), GFP_KERNEL);
+       if (ent)
+               INIT_LIST_HEAD(&ent->list);
+       return ent;
+}
+
 /**
- * aa_unpack - unpack packed binary profile data loaded from user space
+ * aa_unpack - unpack packed binary profile(s) data loaded from user space
  * @udata: user data copied to kmem  (NOT NULL)
  * @size: the size of the user data
+ * @lh: list to place unpacked profiles in a aa_repl_ws
  * @ns: Returns namespace profile is in if specified else NULL (NOT NULL)
  *
- * Unpack user data and return refcounted allocated profile or ERR_PTR
+ * Unpack user data and return refcounted allocated profile(s) stored in
+ * @lh in order of discovery, with the list chain stored in base.list
+ * or error
  *
- * Returns: profile else error pointer if fails to unpack
+ * Returns: profile(s) on @lh else error pointer if fails to unpack
  */
-struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns)
+int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns)
 {
+       struct aa_load_ent *tmp, *ent;
        struct aa_profile *profile = NULL;
        int error;
        struct aa_ext e = {
@@ -713,20 +757,49 @@ struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns)
                .pos = udata,
        };
 
-       error = verify_header(&e, ns);
-       if (error)
-               return ERR_PTR(error);
+       *ns = NULL;
+       while (e.pos < e.end) {
+               void *start;
+               error = verify_header(&e, e.pos == e.start, ns);
+               if (error)
+                       goto fail;
+
+               start = e.pos;
+               profile = unpack_profile(&e);
+               if (IS_ERR(profile)) {
+                       error = PTR_ERR(profile);
+                       goto fail;
+               }
+
+               error = verify_profile(profile);
+               if (error)
+                       goto fail_profile;
+
+               error = aa_calc_profile_hash(profile, e.version, start,
+                                            e.pos - start);
+               if (error)
+                       goto fail_profile;
+
+               ent = aa_load_ent_alloc();
+               if (!ent) {
+                       error = -ENOMEM;
+                       goto fail_profile;
+               }
+
+               ent->new = profile;
+               list_add_tail(&ent->list, lh);
+       }
+
+       return 0;
 
-       profile = unpack_profile(&e);
-       if (IS_ERR(profile))
-               return profile;
+fail_profile:
+       aa_put_profile(profile);
 
-       error = verify_profile(profile);
-       if (error) {
-               aa_put_profile(profile);
-               profile = ERR_PTR(error);
+fail:
+       list_for_each_entry_safe(ent, tmp, lh, list) {
+               list_del_init(&ent->list);
+               aa_load_ent_free(ent);
        }
 
-       /* return refcount */
-       return profile;
+       return error;
 }
index 6c9390179b8909882e8a86e91e4f61349d79dd09..b125acc9aa26cc327572955fb7aa83dbf2c5d09d 100644 (file)
@@ -37,7 +37,7 @@ int aa_getprocattr(struct aa_profile *profile, char **string)
 {
        char *str;
        int len = 0, mode_len = 0, ns_len = 0, name_len;
-       const char *mode_str = profile_mode_names[profile->mode];
+       const char *mode_str = aa_profile_mode_names[profile->mode];
        const char *ns_name = NULL;
        struct aa_namespace *ns = profile->ns;
        struct aa_namespace *current_ns = __aa_current_profile()->ns;
index 32b515766df17c984c6a1c56c86fa67dba4ee25d..dbeb9bc27b24a14b7f546a44843bba2757db77cb 100644 (file)
@@ -129,7 +129,7 @@ static void cap_inode_free_security(struct inode *inode)
 }
 
 static int cap_inode_init_security(struct inode *inode, struct inode *dir,
-                                  const struct qstr *qstr, char **name,
+                                  const struct qstr *qstr, const char **name,
                                   void **value, size_t *len)
 {
        return -EOPNOTSUPP;
index c44b6fe6648e6945518db1a1be1c66b43131b875..b9d613e0ef143b36bd411246d1ce1f42f00738b0 100644 (file)
@@ -768,16 +768,16 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags)
  */
 static int cap_safe_nice(struct task_struct *p)
 {
-       int is_subset;
+       int is_subset, ret = 0;
 
        rcu_read_lock();
        is_subset = cap_issubset(__task_cred(p)->cap_permitted,
                                 current_cred()->cap_permitted);
+       if (!is_subset && !ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE))
+               ret = -EPERM;
        rcu_read_unlock();
 
-       if (!is_subset && !capable(CAP_SYS_NICE))
-               return -EPERM;
-       return 0;
+       return ret;
 }
 
 /**
@@ -824,7 +824,7 @@ int cap_task_setnice(struct task_struct *p, int nice)
  */
 static long cap_prctl_drop(struct cred *new, unsigned long cap)
 {
-       if (!capable(CAP_SETPCAP))
+       if (!ns_capable(current_user_ns(), CAP_SETPCAP))
                return -EPERM;
        if (!cap_valid(cap))
                return -EINVAL;
index df0fa451a8718312ba319d4d27f2edfdf7a3b8e4..af9b6852f4e1bf571b55a2010fd6ab0488119cda 100644 (file)
@@ -418,7 +418,7 @@ int evm_inode_init_security(struct inode *inode,
 
        evm_xattr->value = xattr_data;
        evm_xattr->value_len = sizeof(*xattr_data);
-       evm_xattr->name = kstrdup(XATTR_EVM_SUFFIX, GFP_NOFS);
+       evm_xattr->name = XATTR_EVM_SUFFIX;
        return 0;
 out:
        kfree(xattr_data);
index 94b35aef6871a9978cf21799cfec3385502bc555..4dc31f4f2700626cb951aed5e874f0ce18d8b064 100644 (file)
@@ -348,10 +348,10 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
-       memset(new_xattrs, 0, sizeof new_xattrs);
        if (!initxattrs)
                return security_ops->inode_init_security(inode, dir, qstr,
                                                         NULL, NULL, NULL);
+       memset(new_xattrs, 0, sizeof(new_xattrs));
        lsm_xattr = new_xattrs;
        ret = security_ops->inode_init_security(inode, dir, qstr,
                                                &lsm_xattr->name,
@@ -366,16 +366,14 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
                goto out;
        ret = initxattrs(inode, new_xattrs, fs_data);
 out:
-       for (xattr = new_xattrs; xattr->name != NULL; xattr++) {
-               kfree(xattr->name);
+       for (xattr = new_xattrs; xattr->value != NULL; xattr++)
                kfree(xattr->value);
-       }
        return (ret == -EOPNOTSUPP) ? 0 : ret;
 }
 EXPORT_SYMBOL(security_inode_init_security);
 
 int security_old_inode_init_security(struct inode *inode, struct inode *dir,
-                                    const struct qstr *qstr, char **name,
+                                    const struct qstr *qstr, const char **name,
                                     void **value, size_t *len)
 {
        if (unlikely(IS_PRIVATE(inode)))
index dad36a6ab45f628860ef4c5c097d2a5abce15b4a..fc3e6628a8642e027c992cf500fd4c0a921c85fc 100644 (file)
@@ -746,7 +746,6 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
  * @tclass: target security class
  * @requested: requested permissions, interpreted based on @tclass
  * @auditdata: auxiliary audit data
- * @flags: VFS walk flags
  *
  * Check the AVC to determine whether the @requested permissions are granted
  * for the SID pair (@ssid, @tsid), interpreting the permissions
@@ -756,17 +755,15 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
  * permissions are granted, -%EACCES if any permissions are denied, or
  * another -errno upon other errors.
  */
-int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass,
-                      u32 requested, struct common_audit_data *auditdata,
-                      unsigned flags)
+int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
+                u32 requested, struct common_audit_data *auditdata)
 {
        struct av_decision avd;
        int rc, rc2;
 
        rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
 
-       rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata,
-                       flags);
+       rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
        if (rc2)
                return rc2;
        return rc;
index c956390a9136b75a7fb8ed17ded49c69310b31cf..5b5231068516e46bb529efb3df38051124d2ef85 100644 (file)
@@ -1502,7 +1502,7 @@ static int cred_has_capability(const struct cred *cred,
 
        rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
        if (audit == SECURITY_CAP_AUDIT) {
-               int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
+               int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
                if (rc2)
                        return rc2;
        }
@@ -1525,8 +1525,7 @@ static int task_has_system(struct task_struct *tsk,
 static int inode_has_perm(const struct cred *cred,
                          struct inode *inode,
                          u32 perms,
-                         struct common_audit_data *adp,
-                         unsigned flags)
+                         struct common_audit_data *adp)
 {
        struct inode_security_struct *isec;
        u32 sid;
@@ -1539,7 +1538,7 @@ static int inode_has_perm(const struct cred *cred,
        sid = cred_sid(cred);
        isec = inode->i_security;
 
-       return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
+       return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
@@ -1554,7 +1553,7 @@ static inline int dentry_has_perm(const struct cred *cred,
 
        ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.u.dentry = dentry;
-       return inode_has_perm(cred, inode, av, &ad, 0);
+       return inode_has_perm(cred, inode, av, &ad);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
@@ -1569,7 +1568,7 @@ static inline int path_has_perm(const struct cred *cred,
 
        ad.type = LSM_AUDIT_DATA_PATH;
        ad.u.path = *path;
-       return inode_has_perm(cred, inode, av, &ad, 0);
+       return inode_has_perm(cred, inode, av, &ad);
 }
 
 /* Same as path_has_perm, but uses the inode from the file struct. */
@@ -1581,7 +1580,7 @@ static inline int file_path_has_perm(const struct cred *cred,
 
        ad.type = LSM_AUDIT_DATA_PATH;
        ad.u.path = file->f_path;
-       return inode_has_perm(cred, file_inode(file), av, &ad, 0);
+       return inode_has_perm(cred, file_inode(file), av, &ad);
 }
 
 /* Check whether a task can use an open file descriptor to
@@ -1617,7 +1616,7 @@ static int file_has_perm(const struct cred *cred,
        /* av is zero if only checking access to the descriptor. */
        rc = 0;
        if (av)
-               rc = inode_has_perm(cred, inode, av, &ad, 0);
+               rc = inode_has_perm(cred, inode, av, &ad);
 
 out:
        return rc;
@@ -2587,7 +2586,8 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
 }
 
 static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
-                                      const struct qstr *qstr, char **name,
+                                      const struct qstr *qstr,
+                                      const char **name,
                                       void **value, size_t *len)
 {
        const struct task_security_struct *tsec = current_security();
@@ -2595,7 +2595,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        struct superblock_security_struct *sbsec;
        u32 sid, newsid, clen;
        int rc;
-       char *namep = NULL, *context;
+       char *context;
 
        dsec = dir->i_security;
        sbsec = dir->i_sb->s_security;
@@ -2631,19 +2631,13 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
                return -EOPNOTSUPP;
 
-       if (name) {
-               namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
-               if (!namep)
-                       return -ENOMEM;
-               *name = namep;
-       }
+       if (name)
+               *name = XATTR_SELINUX_SUFFIX;
 
        if (value && len) {
                rc = security_sid_to_context_force(newsid, &context, &clen);
-               if (rc) {
-                       kfree(namep);
+               if (rc)
                        return rc;
-               }
                *value = context;
                *len = clen;
        }
index 92d0ab561db80cb4aa253815149a35e02d6175d1..f53ee3c58d0ffd5099879f2bcdc160c88c209c86 100644 (file)
@@ -130,7 +130,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
                            u16 tclass, u32 requested,
                            struct av_decision *avd,
                            int result,
-                           struct common_audit_data *a, unsigned flags)
+                           struct common_audit_data *a)
 {
        u32 audited, denied;
        audited = avc_audit_required(requested, avd, result, 0, &denied);
@@ -138,7 +138,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
                return 0;
        return slow_avc_audit(ssid, tsid, tclass,
                              requested, audited, denied,
-                             a, flags);
+                             a, 0);
 }
 
 #define AVC_STRICT 1 /* Ignore permissive mode. */
@@ -147,17 +147,9 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
                         unsigned flags,
                         struct av_decision *avd);
 
-int avc_has_perm_flags(u32 ssid, u32 tsid,
-                      u16 tclass, u32 requested,
-                      struct common_audit_data *auditdata,
-                      unsigned);
-
-static inline int avc_has_perm(u32 ssid, u32 tsid,
-                              u16 tclass, u32 requested,
-                              struct common_audit_data *auditdata)
-{
-       return avc_has_perm_flags(ssid, tsid, tclass, requested, auditdata, 0);
-}
+int avc_has_perm(u32 ssid, u32 tsid,
+                u16 tclass, u32 requested,
+                struct common_audit_data *auditdata);
 
 u32 avc_policy_seqno(void);
 
index 339614c76e636f2a6d2ae9a88023502421a936a9..076b8e8a51abd50d833bd2bc6a262349ed902f0e 100644 (file)
@@ -53,6 +53,7 @@
  */
 struct smack_known {
        struct list_head                list;
+       struct hlist_node               smk_hashed;
        char                            *smk_known;
        u32                             smk_secid;
        struct netlbl_lsm_secattr       smk_netlabel;   /* on wire labels */
@@ -167,9 +168,13 @@ struct smk_port_label {
 #define SMACK_CIPSO_DOI_INVALID                -1      /* Not a DOI */
 #define SMACK_CIPSO_DIRECT_DEFAULT     250     /* Arbitrary */
 #define SMACK_CIPSO_MAPPED_DEFAULT     251     /* Also arbitrary */
-#define SMACK_CIPSO_MAXCATVAL          63      /* Bigger gets harder */
 #define SMACK_CIPSO_MAXLEVEL            255     /* CIPSO 2.2 standard */
-#define SMACK_CIPSO_MAXCATNUM           239     /* CIPSO 2.2 standard */
+/*
+ * CIPSO 2.2 standard is 239, but Smack wants to use the
+ * categories in a structured way that limits the value to
+ * the bits in 23 bytes, hence the unusual number.
+ */
+#define SMACK_CIPSO_MAXCATNUM           184     /* 23 * 8 */
 
 /*
  * Flag for transmute access
@@ -222,6 +227,7 @@ char *smk_parse_smack(const char *string, int len);
 int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
 char *smk_import(const char *, int);
 struct smack_known *smk_import_entry(const char *, int);
+void smk_insert_entry(struct smack_known *skp);
 struct smack_known *smk_find_entry(const char *);
 u32 smack_to_secid(const char *);
 
@@ -247,6 +253,9 @@ extern struct list_head smk_netlbladdr_list;
 
 extern struct security_operations smack_ops;
 
+#define SMACK_HASH_SLOTS 16
+extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
+
 /*
  * Is the directory transmuting?
  */
index 6a0377f38620acd318444a399c2fc4ef8227c3db..b3b59b1e93d6e6b056789243b77f0b319e56c982 100644 (file)
@@ -325,6 +325,25 @@ void smack_log(char *subject_label, char *object_label, int request,
 
 DEFINE_MUTEX(smack_known_lock);
 
+struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
+
+/**
+ * smk_insert_entry - insert a smack label into a hash map,
+ *
+ * this function must be called under smack_known_lock
+ */
+void smk_insert_entry(struct smack_known *skp)
+{
+       unsigned int hash;
+       struct hlist_head *head;
+
+       hash = full_name_hash(skp->smk_known, strlen(skp->smk_known));
+       head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
+
+       hlist_add_head_rcu(&skp->smk_hashed, head);
+       list_add_rcu(&skp->list, &smack_known_list);
+}
+
 /**
  * smk_find_entry - find a label on the list, return the list entry
  * @string: a text string that might be a Smack label
@@ -334,12 +353,16 @@ DEFINE_MUTEX(smack_known_lock);
  */
 struct smack_known *smk_find_entry(const char *string)
 {
+       unsigned int hash;
+       struct hlist_head *head;
        struct smack_known *skp;
 
-       list_for_each_entry_rcu(skp, &smack_known_list, list) {
+       hash = full_name_hash(string, strlen(string));
+       head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
+
+       hlist_for_each_entry_rcu(skp, head, smk_hashed)
                if (strcmp(skp->smk_known, string) == 0)
                        return skp;
-       }
 
        return NULL;
 }
@@ -475,7 +498,7 @@ struct smack_known *smk_import_entry(const char *string, int len)
                 * Make sure that the entry is actually
                 * filled before putting it on the list.
                 */
-               list_add_rcu(&skp->list, &smack_known_list);
+               smk_insert_entry(skp);
                goto unlockout;
        }
        /*
index eefbd10e408f18b87d35c35d729fabf088734d65..8825375cc031709b3918cd073cd574708c3f0405 100644 (file)
@@ -582,7 +582,7 @@ static void smack_inode_free_security(struct inode *inode)
  * Returns 0 if it all works out, -ENOMEM if there's no memory
  */
 static int smack_inode_init_security(struct inode *inode, struct inode *dir,
-                                    const struct qstr *qstr, char **name,
+                                    const struct qstr *qstr, const char **name,
                                     void **value, size_t *len)
 {
        struct inode_smack *issp = inode->i_security;
@@ -591,11 +591,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
        char *dsp = smk_of_inode(dir);
        int may;
 
-       if (name) {
-               *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_NOFS);
-               if (*name == NULL)
-                       return -ENOMEM;
-       }
+       if (name)
+               *name = XATTR_SMACK_SUFFIX;
 
        if (value) {
                rcu_read_lock();
@@ -3065,6 +3062,8 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
 {
        struct smack_known *skp;
        int found = 0;
+       int acat;
+       int kcat;
 
        if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {
                /*
@@ -3081,12 +3080,28 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
                list_for_each_entry(skp, &smack_known_list, list) {
                        if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl)
                                continue;
-                       if (memcmp(sap->attr.mls.cat,
-                               skp->smk_netlabel.attr.mls.cat,
-                               SMK_CIPSOLEN) != 0)
-                               continue;
-                       found = 1;
-                       break;
+                       /*
+                        * Compare the catsets. Use the netlbl APIs.
+                        */
+                       if ((sap->flags & NETLBL_SECATTR_MLS_CAT) == 0) {
+                               if ((skp->smk_netlabel.flags &
+                                    NETLBL_SECATTR_MLS_CAT) == 0)
+                                       found = 1;
+                               break;
+                       }
+                       for (acat = -1, kcat = -1; acat == kcat; ) {
+                               acat = netlbl_secattr_catmap_walk(
+                                       sap->attr.mls.cat, acat + 1);
+                               kcat = netlbl_secattr_catmap_walk(
+                                       skp->smk_netlabel.attr.mls.cat,
+                                       kcat + 1);
+                               if (acat < 0 || kcat < 0)
+                                       break;
+                       }
+                       if (acat == kcat) {
+                               found = 1;
+                               break;
+                       }
                }
                rcu_read_unlock();
 
@@ -3877,12 +3892,12 @@ static __init void init_smack_known_list(void)
        /*
         * Create the known labels list
         */
-       list_add(&smack_known_huh.list, &smack_known_list);
-       list_add(&smack_known_hat.list, &smack_known_list);
-       list_add(&smack_known_star.list, &smack_known_list);
-       list_add(&smack_known_floor.list, &smack_known_list);
-       list_add(&smack_known_invalid.list, &smack_known_list);
-       list_add(&smack_known_web.list, &smack_known_list);
+       smk_insert_entry(&smack_known_huh);
+       smk_insert_entry(&smack_known_hat);
+       smk_insert_entry(&smack_known_star);
+       smk_insert_entry(&smack_known_floor);
+       smk_insert_entry(&smack_known_invalid);
+       smk_insert_entry(&smack_known_web);
 }
 
 /**
index ab167037b2ddcc99b9dc733b69f1243ee65843fb..80f4b4a45725bddba4f094d2fefdd4701c07cb6b 100644 (file)
@@ -368,56 +368,43 @@ static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule,
  * @data: string to be parsed, null terminated
  * @rule: Will be filled with Smack parsed rule
  * @import: if non-zero, import labels
- * @change: if non-zero, data is from /smack/change-rule
+ * @tokens: numer of substrings expected in data
  *
- * Returns 0 on success, -1 on failure
+ * Returns number of processed bytes on success, -1 on failure.
  */
-static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule,
-                               int import, int change)
+static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule,
+                               int import, int tokens)
 {
-       char *subject;
-       char *object;
-       char *access1;
-       char *access2;
-       int datalen;
-       int rc = -1;
+       ssize_t cnt = 0;
+       char *tok[4];
+       int i;
 
-       /* This is inefficient */
-       datalen = strlen(data);
+       /*
+        * Parsing the rule in-place, filling all white-spaces with '\0'
+        */
+       for (i = 0; i < tokens; ++i) {
+               while (isspace(data[cnt]))
+                       data[cnt++] = '\0';
 
-       /* Our first element can be 64 + \0 with no spaces */
-       subject = kzalloc(datalen + 1, GFP_KERNEL);
-       if (subject == NULL)
-               return -1;
-       object = kzalloc(datalen, GFP_KERNEL);
-       if (object == NULL)
-               goto free_out_s;
-       access1 = kzalloc(datalen, GFP_KERNEL);
-       if (access1 == NULL)
-               goto free_out_o;
-       access2 = kzalloc(datalen, GFP_KERNEL);
-       if (access2 == NULL)
-               goto free_out_a;
-
-       if (change) {
-               if (sscanf(data, "%s %s %s %s",
-                       subject, object, access1, access2) == 4)
-                       rc = smk_fill_rule(subject, object, access1, access2,
-                               rule, import, 0);
-       } else {
-               if (sscanf(data, "%s %s %s", subject, object, access1) == 3)
-                       rc = smk_fill_rule(subject, object, access1, NULL,
-                               rule, import, 0);
+               if (data[cnt] == '\0')
+                       /* Unexpected end of data */
+                       return -1;
+
+               tok[i] = data + cnt;
+
+               while (data[cnt] && !isspace(data[cnt]))
+                       ++cnt;
        }
+       while (isspace(data[cnt]))
+               data[cnt++] = '\0';
 
-       kfree(access2);
-free_out_a:
-       kfree(access1);
-free_out_o:
-       kfree(object);
-free_out_s:
-       kfree(subject);
-       return rc;
+       while (i < 4)
+               tok[i++] = NULL;
+
+       if (smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0))
+               return -1;
+
+       return cnt;
 }
 
 #define SMK_FIXED24_FMT        0       /* Fixed 24byte label format */
@@ -447,11 +434,12 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
                                        struct list_head *rule_list,
                                        struct mutex *rule_lock, int format)
 {
-       struct smack_parsed_rule *rule;
+       struct smack_parsed_rule rule;
        char *data;
-       int datalen;
-       int rc = -EINVAL;
-       int load = 0;
+       int rc;
+       int trunc = 0;
+       int tokens;
+       ssize_t cnt = 0;
 
        /*
         * No partial writes.
@@ -466,11 +454,14 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
                 */
                if (count != SMK_OLOADLEN && count != SMK_LOADLEN)
                        return -EINVAL;
-               datalen = SMK_LOADLEN;
-       } else
-               datalen = count + 1;
+       } else {
+               if (count >= PAGE_SIZE) {
+                       count = PAGE_SIZE - 1;
+                       trunc = 1;
+               }
+       }
 
-       data = kzalloc(datalen, GFP_KERNEL);
+       data = kmalloc(count + 1, GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
 
@@ -479,47 +470,49 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
                goto out;
        }
 
-       rule = kzalloc(sizeof(*rule), GFP_KERNEL);
-       if (rule == NULL) {
-               rc = -ENOMEM;
-               goto out;
+       /*
+        * In case of parsing only part of user buf,
+        * avoid having partial rule at the data buffer
+        */
+       if (trunc) {
+               while (count > 0 && (data[count - 1] != '\n'))
+                       --count;
+               if (count == 0) {
+                       rc = -EINVAL;
+                       goto out;
+               }
        }
 
-       if (format == SMK_LONG_FMT) {
-               /*
-                * Be sure the data string is terminated.
-                */
-               data[count] = '\0';
-               if (smk_parse_long_rule(data, rule, 1, 0))
-                       goto out_free_rule;
-       } else if (format == SMK_CHANGE_FMT) {
-               data[count] = '\0';
-               if (smk_parse_long_rule(data, rule, 1, 1))
-                       goto out_free_rule;
-       } else {
-               /*
-                * More on the minor hack for backward compatibility
-                */
-               if (count == (SMK_OLOADLEN))
-                       data[SMK_OLOADLEN] = '-';
-               if (smk_parse_rule(data, rule, 1))
-                       goto out_free_rule;
-       }
+       data[count] = '\0';
+       tokens = (format == SMK_CHANGE_FMT ? 4 : 3);
+       while (cnt < count) {
+               if (format == SMK_FIXED24_FMT) {
+                       rc = smk_parse_rule(data, &rule, 1);
+                       if (rc != 0) {
+                               rc = -EINVAL;
+                               goto out;
+                       }
+                       cnt = count;
+               } else {
+                       rc = smk_parse_long_rule(data + cnt, &rule, 1, tokens);
+                       if (rc <= 0) {
+                               rc = -EINVAL;
+                               goto out;
+                       }
+                       cnt += rc;
+               }
 
-       if (rule_list == NULL) {
-               load = 1;
-               rule_list = &rule->smk_subject->smk_rules;
-               rule_lock = &rule->smk_subject->smk_rules_lock;
-       }
+               if (rule_list == NULL)
+                       rc = smk_set_access(&rule, &rule.smk_subject->smk_rules,
+                               &rule.smk_subject->smk_rules_lock, 1);
+               else
+                       rc = smk_set_access(&rule, rule_list, rule_lock, 0);
 
-       rc = smk_set_access(rule, rule_list, rule_lock, load);
-       if (rc == 0) {
-               rc = count;
-               goto out;
+               if (rc)
+                       goto out;
        }
 
-out_free_rule:
-       kfree(rule);
+       rc = cnt;
 out:
        kfree(data);
        return rc;
@@ -901,7 +894,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
        for (i = 0; i < catlen; i++) {
                rule += SMK_DIGITLEN;
                ret = sscanf(rule, "%u", &cat);
-               if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL)
+               if (ret != 1 || cat > SMACK_CIPSO_MAXCATNUM)
                        goto out;
 
                smack_catset_bit(cat, mapcatset);
@@ -1840,7 +1833,6 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
 {
        struct smack_parsed_rule rule;
        char *data;
-       char *cod;
        int res;
 
        data = simple_transaction_get(file, buf, count);
@@ -1853,18 +1845,12 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
                res = smk_parse_rule(data, &rule, 0);
        } else {
                /*
-                * Copy the data to make sure the string is terminated.
+                * simple_transaction_get() returns null-terminated data
                 */
-               cod = kzalloc(count + 1, GFP_KERNEL);
-               if (cod == NULL)
-                       return -ENOMEM;
-               memcpy(cod, data, count);
-               cod[count] = '\0';
-               res = smk_parse_long_rule(cod, &rule, 0, 0);
-               kfree(cod);
+               res = smk_parse_long_rule(data, &rule, 0, 3);
        }
 
-       if (res)
+       if (res < 0)
                return -EINVAL;
 
        res = smk_access(rule.smk_subject, rule.smk_object,
index 98969541cbcc9c62ff81afb9818d2399dd6e7eb0..bea523a5d852e11f9d06e1d682e065b699f347c8 100644 (file)
@@ -139,6 +139,18 @@ static int snd_compr_open(struct inode *inode, struct file *f)
 static int snd_compr_free(struct inode *inode, struct file *f)
 {
        struct snd_compr_file *data = f->private_data;
+       struct snd_compr_runtime *runtime = data->stream.runtime;
+
+       switch (runtime->state) {
+       case SNDRV_PCM_STATE_RUNNING:
+       case SNDRV_PCM_STATE_DRAINING:
+       case SNDRV_PCM_STATE_PAUSED:
+               data->stream.ops->trigger(&data->stream, SNDRV_PCM_TRIGGER_STOP);
+               break;
+       default:
+               break;
+       }
+
        data->stream.ops->free(&data->stream);
        kfree(data->stream.runtime->buffer);
        kfree(data->stream.runtime);
@@ -837,7 +849,8 @@ static int snd_compress_dev_disconnect(struct snd_device *device)
        struct snd_compr *compr;
 
        compr = device->device_data;
-       snd_unregister_device(compr->direction, compr->card, compr->device);
+       snd_unregister_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
+               compr->device);
        return 0;
 }
 
index 445ca481d8d30116bc075e3ac2cee881f1149863..bf578ba2677e72566187619e1e0515afe93fdfd6 100644 (file)
@@ -175,6 +175,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
 { 0x54524106, 0xffffffff, "TR28026",           NULL,           NULL },
 { 0x54524108, 0xffffffff, "TR28028",           patch_tritech_tr28028,  NULL }, // added by xin jin [07/09/99]
 { 0x54524123, 0xffffffff, "TR28602",           NULL,           NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
+{ 0x54584e03, 0xffffffff, "TLV320AIC27",       NULL,           NULL },
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",       NULL,           NULL },
 { 0x56494161, 0xffffffff, "VIA1612A",          NULL,           NULL }, // modified ICE1232 with S/PDIF
 { 0x56494170, 0xffffffff, "VIA1617A",          patch_vt1617a,  NULL }, // modified VT1616 with S/PDIF
index ac41e9cdc976a1c190c51684519abb9c475c2c59..26ad4f0aade3fcf2c26940c008fae9a55c63244c 100644 (file)
@@ -3531,7 +3531,7 @@ static int create_capture_mixers(struct hda_codec *codec)
                if (!multi)
                        err = create_single_cap_vol_ctl(codec, n, vol, sw,
                                                        inv_dmic);
-               else if (!multi_cap_vol)
+               else if (!multi_cap_vol && !inv_dmic)
                        err = create_bind_cap_vol_ctl(codec, n, vol, sw);
                else
                        err = create_multi_cap_vol_ctl(codec);
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..18d9725015855c0ce3f33d174a3dfcd55836efeb 100644 (file)
@@ -111,6 +111,9 @@ enum {
 /* 0x0009 - 0x0014 -> 12 test regs */
 /* 0x0015 - visibility reg */
 
+/* Cirrus Logic CS4208 */
+#define CS4208_VENDOR_NID      0x24
+
 /*
  * Cirrus Logic CS4210
  *
@@ -169,7 +172,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,
@@ -223,6 +226,16 @@ static const struct hda_verb cs_coef_init_verbs[] = {
        {} /* terminator */
 };
 
+static const struct hda_verb cs4208_coef_init_verbs[] = {
+       {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
+       {0x24, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
+       {0x24, AC_VERB_SET_COEF_INDEX, 0x0033},
+       {0x24, AC_VERB_SET_PROC_COEF, 0x0001}, /* A1 ICS */
+       {0x24, AC_VERB_SET_COEF_INDEX, 0x0034},
+       {0x24, AC_VERB_SET_PROC_COEF, 0x1C01}, /* A1 Enable, A Thresh = 300mV */
+       {} /* terminator */
+};
+
 /* Errata: CS4207 rev C0/C1/C2 Silicon
  *
  * http://www.cirrus.com/en/pubs/errata/ER880C3.pdf
@@ -291,10 +304,13 @@ 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);
+       } else if (spec->vendor_nid == CS4208_VENDOR_NID) {
+               snd_hda_sequence_write(codec, cs4208_coef_init_verbs);
+       }
 
        snd_hda_gen_init(codec);
 
@@ -307,8 +323,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;
 }
@@ -431,6 +449,29 @@ static const struct hda_pintbl mba42_pincfgs[] = {
        {} /* terminator */
 };
 
+static const struct hda_pintbl mba6_pincfgs[] = {
+       { 0x10, 0x032120f0 }, /* HP */
+       { 0x11, 0x500000f0 },
+       { 0x12, 0x90100010 }, /* Speaker */
+       { 0x13, 0x500000f0 },
+       { 0x14, 0x500000f0 },
+       { 0x15, 0x770000f0 },
+       { 0x16, 0x770000f0 },
+       { 0x17, 0x430000f0 },
+       { 0x18, 0x43ab9030 }, /* Mic */
+       { 0x19, 0x770000f0 },
+       { 0x1a, 0x770000f0 },
+       { 0x1b, 0x770000f0 },
+       { 0x1c, 0x90a00090 },
+       { 0x1d, 0x500000f0 },
+       { 0x1e, 0x500000f0 },
+       { 0x1f, 0x500000f0 },
+       { 0x20, 0x500000f0 },
+       { 0x21, 0x430000f0 },
+       { 0x22, 0x430000f0 },
+       {} /* terminator */
+};
+
 static void cs420x_fixup_gpio_13(struct hda_codec *codec,
                                 const struct hda_fixup *fix, int action)
 {
@@ -551,6 +592,100 @@ static int patch_cs420x(struct hda_codec *codec)
        return err;
 }
 
+/*
+ * CS4208 support:
+ * Its layout is no longer compatible with CS4206/CS4207
+ */
+enum {
+       CS4208_MBA6,
+       CS4208_GPIO0,
+};
+
+static const struct hda_model_fixup cs4208_models[] = {
+       { .id = CS4208_GPIO0, .name = "gpio0" },
+       { .id = CS4208_MBA6, .name = "mba6" },
+       {}
+};
+
+static const struct snd_pci_quirk cs4208_fixup_tbl[] = {
+       /* codec SSID */
+       SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6),
+       SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6),
+       {} /* 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_MBA6] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = mba6_pincfgs,
+               .chained = true,
+               .chain_id = CS4208_GPIO0,
+       },
+       [CS4208_GPIO0] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs4208_fixup_gpio0,
+       },
+};
+
+/* correct the 0dB offset of input pins */
+static void cs4208_fix_amp_caps(struct hda_codec *codec, hda_nid_t adc)
+{
+       unsigned int caps;
+
+       caps = query_amp_caps(codec, adc, HDA_INPUT);
+       caps &= ~(AC_AMPCAP_OFFSET);
+       caps |= 0x02;
+       snd_hda_override_amp_caps(codec, adc, HDA_INPUT, caps);
+}
+
+static int patch_cs4208(struct hda_codec *codec)
+{
+       struct cs_spec *spec;
+       int err;
+
+       spec = cs_alloc_spec(codec, CS4208_VENDOR_NID);
+       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);
+
+       snd_hda_override_wcaps(codec, 0x18,
+                              get_wcaps(codec, 0x18) | AC_WCAP_STEREO);
+       cs4208_fix_amp_caps(codec, 0x18);
+       cs4208_fix_amp_caps(codec, 0x1b);
+       cs4208_fix_amp_caps(codec, 0x1c);
+
+       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 +1126,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 +1134,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 4edd2d0f9a3ce66e625f7576b3b7053548397a51..ec68eaea0336a008c78fb05c03a4d6c0e3f99c2a 100644 (file)
@@ -3231,6 +3231,7 @@ enum {
        CXT_FIXUP_INC_MIC_BOOST,
        CXT_FIXUP_HEADPHONE_MIC_PIN,
        CXT_FIXUP_HEADPHONE_MIC,
+       CXT_FIXUP_GPIO1,
 };
 
 static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
@@ -3375,6 +3376,15 @@ static const struct hda_fixup cxt_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cxt_fixup_headphone_mic,
        },
+       [CXT_FIXUP_GPIO1] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 },
+                       { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 },
+                       { 0x01, AC_VERB_SET_GPIO_DATA, 0x01 },
+                       { }
+               },
+       },
 };
 
 static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -3384,6 +3394,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = {
 
 static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_GPIO1),
        SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
index 9a58893d52a7c6325a69837ccae7f049087747e1..50173d412ac5c0d5fb7095b3e3004e2c63c319a0 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;
@@ -929,6 +936,14 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
                return;
        }
 
+       /*
+        * always configure channel mapping, it may have been changed by the
+        * user in the meantime
+        */
+       hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
+                                  channels, per_pin->chmap,
+                                  per_pin->chmap_set);
+
        /*
         * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
         * sizeof(*dp_ai) to avoid partial match/update problems when
@@ -940,20 +955,10 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
                            "pin=%d channels=%d\n",
                            pin_nid,
                            channels);
-               hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
-                                          channels, per_pin->chmap,
-                                          per_pin->chmap_set);
                hdmi_stop_infoframe_trans(codec, pin_nid);
                hdmi_fill_audio_infoframe(codec, pin_nid,
                                            ai.bytes, sizeof(ai));
                hdmi_start_infoframe_trans(codec, pin_nid);
-       } else {
-               /* For non-pcm audio switch, setup new channel mapping
-                * accordingly */
-               if (per_pin->non_pcm != non_pcm)
-                       hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
-                                                  channels, per_pin->chmap,
-                                                  per_pin->chmap_set);
        }
 
        per_pin->non_pcm = non_pcm;
@@ -1033,10 +1038,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 +1057,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 +1073,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,
@@ -1161,32 +1147,43 @@ static int hdmi_choose_cvt(struct hda_codec *codec,
 }
 
 static void haswell_config_cvts(struct hda_codec *codec,
-                       int pin_id, int mux_id)
+                       hda_nid_t pin_nid, int mux_idx)
 {
        struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin;
-       int pin_idx, mux_idx;
-       int curr;
-       int err;
+       hda_nid_t nid, end_nid;
+       int cvt_idx, curr;
+       struct hdmi_spec_per_cvt *per_cvt;
 
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               per_pin = get_pin(spec, pin_idx);
+       /* configure all pins, including "no physical connection" ones */
+       end_nid = codec->start_nid + codec->num_nodes;
+       for (nid = codec->start_nid; nid < end_nid; nid++) {
+               unsigned int wid_caps = get_wcaps(codec, nid);
+               unsigned int wid_type = get_wcaps_type(wid_caps);
 
-               if (pin_idx == pin_id)
+               if (wid_type != AC_WID_PIN)
                        continue;
 
-               curr = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+               if (nid == pin_nid)
+                       continue;
+
+               curr = snd_hda_codec_read(codec, nid, 0,
                                          AC_VERB_GET_CONNECT_SEL, 0);
+               if (curr != mux_idx)
+                       continue;
 
-               /* Choose another unused converter */
-               if (curr == mux_id) {
-                       err = hdmi_choose_cvt(codec, pin_idx, NULL, &mux_idx);
-                       if (err < 0)
-                               return;
-                       snd_printdd("HDMI: choose converter %d for pin %d\n", mux_idx, pin_idx);
-                       snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+               /* choose an unassigned converter. The conveters in the
+                * connection list are in the same order as in the codec.
+                */
+               for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+                       per_cvt = get_cvt(spec, cvt_idx);
+                       if (!per_cvt->assigned) {
+                               snd_printdd("choose cvt %d for pin nid %d\n",
+                                       cvt_idx, nid);
+                               snd_hda_codec_write_cache(codec, nid, 0,
                                            AC_VERB_SET_CONNECT_SEL,
-                                           mux_idx);
+                                           cvt_idx);
+                               break;
+                       }
                }
        }
 }
@@ -1227,8 +1224,8 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
                            mux_idx);
 
        /* configure unused pins to choose other converters */
-       if (codec->vendor_id == 0x80862807)
-               haswell_config_cvts(codec, pin_idx, mux_idx);
+       if (is_haswell(codec))
+               haswell_config_cvts(codec, per_pin->pin_nid, mux_idx);
 
        snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
 
@@ -1358,14 +1355,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 +1398,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 +2007,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 +2018,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..bf313bea70858f8a4abd18ef6c60beca6668fea1 100644 (file)
@@ -2819,6 +2819,15 @@ static void alc269_fixup_hweq(struct hda_codec *codec,
        alc_write_coef_idx(codec, 0x1e, coef | 0x80);
 }
 
+static void alc269_fixup_headset_mic(struct hda_codec *codec,
+                                      const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+}
+
 static void alc271_fixup_dmic(struct hda_codec *codec,
                              const struct hda_fixup *fix, int action)
 {
@@ -3439,10 +3448,72 @@ static void alc283_fixup_chromebook(struct hda_codec *codec,
                /* Set to manual mode */
                val = alc_read_coef_idx(codec, 0x06);
                alc_write_coef_idx(codec, 0x06, val & ~0x000c);
+               /* Enable Line1 input control by verb */
+               val = alc_read_coef_idx(codec, 0x1a);
+               alc_write_coef_idx(codec, 0x1a, val | (1 << 4));
+               break;
+       }
+}
+
+/* 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;
        }
 }
 
+static void alc290_fixup_mono_speakers(struct hda_codec *codec,
+                                      const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               /* Remove DAC node 0x03, as it seems to be
+                  giving mono output */
+               snd_hda_override_wcaps(codec, 0x03, 0);
+}
+
 enum {
        ALC269_FIXUP_SONY_VAIO,
        ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -3454,6 +3525,7 @@ enum {
        ALC271_FIXUP_DMIC,
        ALC269_FIXUP_PCM_44K,
        ALC269_FIXUP_STEREO_DMIC,
+       ALC269_FIXUP_HEADSET_MIC,
        ALC269_FIXUP_QUANTA_MUTE,
        ALC269_FIXUP_LIFEBOOK,
        ALC269_FIXUP_AMIC,
@@ -3466,9 +3538,11 @@ enum {
        ALC269_FIXUP_HP_GPIO_LED,
        ALC269_FIXUP_INV_DMIC,
        ALC269_FIXUP_LENOVO_DOCK,
+       ALC286_FIXUP_SONY_MIC_NO_PRESENCE,
        ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
        ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
        ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
+       ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
        ALC269_FIXUP_HEADSET_MODE,
        ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC,
        ALC269_FIXUP_ASUS_X101_FUNC,
@@ -3480,6 +3554,9 @@ enum {
        ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
        ALC269VB_FIXUP_ORDISSIMO_EVE2,
        ALC283_FIXUP_CHROME_BOOK,
+       ALC282_FIXUP_ASUS_TX300,
+       ALC283_FIXUP_INT_MIC,
+       ALC290_FIXUP_MONO_SPEAKERS,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -3548,6 +3625,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_stereo_dmic,
        },
+       [ALC269_FIXUP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_headset_mic,
+       },
        [ALC269_FIXUP_QUANTA_MUTE] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_quanta_mute,
@@ -3657,6 +3738,15 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
        },
+       [ALC269_FIXUP_DELL3_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
        [ALC269_FIXUP_HEADSET_MODE] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode,
@@ -3665,6 +3755,15 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode_no_hp_mic,
        },
+       [ALC286_FIXUP_SONY_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
        [ALC269_FIXUP_ASUS_X101_FUNC] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_x101_headset_mic,
@@ -3735,6 +3834,26 @@ 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,
+       },
+       [ALC283_FIXUP_INT_MIC] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x1a},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x0011},
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
+       },
+       [ALC290_FIXUP_MONO_SPEAKERS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc290_fixup_mono_speakers,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -3776,6 +3895,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_MONO_SPEAKERS),
        SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -3784,6 +3904,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),
@@ -3797,6 +3918,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101),
+       SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
        SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
        SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
@@ -3818,7 +3940,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
@@ -3882,6 +4004,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC269_FIXUP_STEREO_DMIC, .name = "alc269-dmic"},
        {.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"},
        {.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"},
+       {.id = ALC269_FIXUP_HEADSET_MIC, .name = "headset-mic"},
        {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
        {.id = ALC269_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
        {.id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
@@ -4499,6 +4622,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
+       SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_ASUS_MODE4),
        SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
        SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
        SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
index 4f255dfee4504454702bfdec305b1b72820a26ac..f59a321a6d6af04d6dce32751410e4eb3f9d9df0 100644 (file)
@@ -4845,6 +4845,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
                        if ((err = hdsp_get_iobox_version(hdsp)) < 0)
                                return err;
                }
+               memset(&hdsp_version, 0, sizeof(hdsp_version));
                hdsp_version.io_type = hdsp->io_type;
                hdsp_version.firmware_rev = hdsp->firmware_rev;
                if ((err = copy_to_user(argp, &hdsp_version, sizeof(hdsp_version))))
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 c02405cc007db2c88c14b25d17eff81b270f550b..5810a0603f2f1eb17ef5eece60d97ba7f6687e04 100644 (file)
@@ -88,6 +88,7 @@ static int bfin_i2s_hw_params(struct snd_pcm_substream *substream,
        case SNDRV_PCM_FORMAT_S8:
                param.spctl |= 0x70;
                sport->wdsize = 1;
+               break;
        case SNDRV_PCM_FORMAT_S16_LE:
                param.spctl |= 0xf0;
                sport->wdsize = 2;
index 8af04343cc1ac9eab35fe951fd079fd1954da462..259d1ac4492fc610a1454567bdabd52f56dbae5a 100644 (file)
@@ -349,6 +349,9 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
        val = ucontrol->value.integer.value[0];
        val2 = ucontrol->value.integer.value[1];
 
+       if (val >= ARRAY_SIZE(st_table) || val2 >= ARRAY_SIZE(st_table))
+               return -EINVAL;
+
        err = snd_soc_update_bits(codec, reg, 0x3f, st_table[val].m);
        if (err < 0)
                return err;
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 b8ba0adacfce1229989f0114ce25eb9711f61d16..80555d7551e68018d5e66485eea1507b10c35b92 100644 (file)
@@ -1225,13 +1225,18 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
        struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
        struct device *dev = codec->dev;
        bool apply_fir, apply_iir;
-       int req, status;
+       unsigned int req;
+       int status;
 
        dev_dbg(dev, "%s: Enter.\n", __func__);
 
        mutex_lock(&drvdata->anc_lock);
 
        req = ucontrol->value.integer.value[0];
+       if (req >= ARRAY_SIZE(enum_anc_state)) {
+               status = -EINVAL;
+               goto cleanup;
+       }
        if (req != ANC_APPLY_FIR_IIR && req != ANC_APPLY_FIR &&
                req != ANC_APPLY_IIR) {
                dev_err(dev, "%s: ERROR: Unsupported status to set '%s'!\n",
index 41cdd164297046c3045c9463ab6183810e02a126..8dbcacd44e6aa5cbf5de1fba91ebdf16c1592ff8 100644 (file)
@@ -1863,7 +1863,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
        struct max98095_pdata *pdata = max98095->pdata;
        int channel = max98095_get_eq_channel(kcontrol->id.name);
        struct max98095_cdata *cdata;
-       int sel = ucontrol->value.integer.value[0];
+       unsigned int sel = ucontrol->value.integer.value[0];
        struct max98095_eq_cfg *coef_set;
        int fs, best, best_val, i;
        int regmask, regsave;
@@ -2016,7 +2016,7 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
        struct max98095_pdata *pdata = max98095->pdata;
        int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
        struct max98095_cdata *cdata;
-       int sel = ucontrol->value.integer.value[0];
+       unsigned int sel = ucontrol->value.integer.value[0];
        struct max98095_biquad_cfg *coef_set;
        int fs, best, best_val, i;
        int regmask, regsave;
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 46c5b4fdfc5298e61008032fe903c0191f886d31..ca1be1d9dcf0349b608f77367f5330ca7c2c6308 100644 (file)
@@ -62,7 +62,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        struct device_node *ssi_np, *codec_np;
        struct platform_device *ssi_pdev;
        struct i2c_client *codec_dev;
-       struct imx_sgtl5000_data *data;
+       struct imx_sgtl5000_data *data = NULL;
        int int_port, ext_port;
        int ret;
 
@@ -128,7 +128,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
                goto fail;
        }
 
-       data->codec_clk = devm_clk_get(&codec_dev->dev, NULL);
+       data->codec_clk = clk_get(&codec_dev->dev, NULL);
        if (IS_ERR(data->codec_clk)) {
                ret = PTR_ERR(data->codec_clk);
                goto fail;
@@ -172,6 +172,8 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        return 0;
 
 fail:
+       if (data && !IS_ERR(data->codec_clk))
+               clk_put(data->codec_clk);
        if (ssi_np)
                of_node_put(ssi_np);
        if (codec_np)
@@ -185,6 +187,7 @@ static int imx_sgtl5000_remove(struct platform_device *pdev)
        struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
 
        snd_soc_unregister_card(&data->card);
+       clk_put(data->codec_clk);
 
        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 4d0561312f3be0a9f383928b3d74f80a44cdd3b3..1a38be0d0ca8fbf0724bbec4087569ee418d39a2 100644 (file)
@@ -1380,7 +1380,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
                                return -ENODEV;
 
                        list_add(&cpu_dai->dapm.list, &card->dapm_list);
-                       snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai);
                }
 
                if (cpu_dai->driver->probe) {
index d0323a693ba20f4719731369f85324e9ba582096..999550bbad40e66f259d9ed2b044ed478e377d72 100644 (file)
@@ -262,7 +262,9 @@ static int usb_stream_hwdep_mmap(struct snd_hwdep *hw,
        }
 
        area->vm_ops = &usb_stream_hwdep_vm_ops;
-       area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+       area->vm_flags |= VM_DONTDUMP;
+       if (!read)
+               area->vm_flags |= VM_DONTEXPAND;
        area->vm_private_data = us122l;
        atomic_inc(&us122l->mmap_count);
 out:
index 63fb5219f0f8aad7a844eb1942b5cd728be678dc..6234a51625b1b6a556f252c2fea3a150db1bdbc1 100644 (file)
@@ -299,19 +299,6 @@ static void usX2Y_error_urb_status(struct usX2Ydev *usX2Y,
        usX2Y_clients_stop(usX2Y);
 }
 
-static void usX2Y_error_sequence(struct usX2Ydev *usX2Y,
-                                struct snd_usX2Y_substream *subs, struct urb *urb)
-{
-       snd_printk(KERN_ERR
-"Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n"
-"Most probably some urb of usb-frame %i is still missing.\n"
-"Cause could be too long delays in usb-hcd interrupt handling.\n",
-                  usb_get_current_frame_number(usX2Y->dev),
-                  subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
-                  usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame);
-       usX2Y_clients_stop(usX2Y);
-}
-
 static void i_usX2Y_urb_complete(struct urb *urb)
 {
        struct snd_usX2Y_substream *subs = urb->context;
@@ -328,12 +315,9 @@ static void i_usX2Y_urb_complete(struct urb *urb)
                usX2Y_error_urb_status(usX2Y, subs, urb);
                return;
        }
-       if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
-               subs->completed_urb = urb;
-       else {
-               usX2Y_error_sequence(usX2Y, subs, urb);
-               return;
-       }
+
+       subs->completed_urb = urb;
+
        {
                struct snd_usX2Y_substream *capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE],
                        *playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
index f2a1acdc4d839f22eb7fa83d63b5f35ce367c5cd..814d0e887c62e5c451c3ff7cc4b8f448c3a45007 100644 (file)
@@ -244,13 +244,8 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
                usX2Y_error_urb_status(usX2Y, subs, urb);
                return;
        }
-       if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
-               subs->completed_urb = urb;
-       else {
-               usX2Y_error_sequence(usX2Y, subs, urb);
-               return;
-       }
 
+       subs->completed_urb = urb;
        capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
        capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
        playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
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 099e7cd022e46d47260103b226b3410beac27133..7c43479623537af4f0d4179f4cce195cbea3e9b1 100644 (file)
@@ -5,7 +5,6 @@
 #include <stdbool.h>
 #include <sys/vfs.h>
 #include <sys/mount.h>
-#include <linux/magic.h>
 #include <linux/kernel.h>
 
 #include "debugfs.h"
index c5dc1ad1b8d73bc66ae92d78d522af7f15155126..64c043b7a43848f17a023dcf9479dbd77f96d7be 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))
@@ -769,6 +770,7 @@ check: $(OUTPUT)common-cmds.h
 install-bin: all
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
        $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
+       $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
        $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 ifndef NO_LIBPERL
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
index 9570c2b0f83c580454e2610cb3c07a4d7443ee19..b2519e49424f4c42bb389de846d21c8337773036 100644 (file)
@@ -32,7 +32,7 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
                             struct perf_tsc_conversion *tc)
 {
-       bool cap_usr_time_zero;
+       bool cap_user_time_zero;
        u32 seq;
        int i = 0;
 
@@ -42,7 +42,7 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
                tc->time_mult = pc->time_mult;
                tc->time_shift = pc->time_shift;
                tc->time_zero = pc->time_zero;
-               cap_usr_time_zero = pc->cap_usr_time_zero;
+               cap_user_time_zero = pc->cap_user_time_zero;
                rmb();
                if (pc->lock == seq && !(seq & 1))
                        break;
@@ -52,7 +52,7 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
                }
        }
 
-       if (!cap_usr_time_zero)
+       if (!cap_user_time_zero)
                return -EOPNOTSUPP;
 
        return 0;
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..afe377b2884f740b0c469a367ab3938d99f7df0e 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,
@@ -308,8 +321,6 @@ found:
        return perf_event__repipe(tool, event_sw, &sample_sw, machine);
 }
 
-extern volatile int session_done;
-
 static void sig_handler(int sig __maybe_unused)
 {
        session_done = 1;
@@ -339,6 +350,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 +402,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 c2dff9cb1f2ce1ac150401d7b859229beb53998e..9b5f077fee5b1b65a4e51b48ef1af0727b8c134b 100644 (file)
@@ -101,7 +101,7 @@ static int setup_cpunode_map(void)
 
        dir1 = opendir(PATH_SYS_NODE);
        if (!dir1)
-               return -1;
+               return 0;
 
        while ((dent1 = readdir(dir1)) != NULL) {
                if (dent1->d_type != DT_DIR ||
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..72eae7498c09419c8f1f77a7a005c6dcbbb5eb4b 100644 (file)
@@ -401,8 +401,6 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
        return 0;
 }
 
-extern volatile int session_done;
-
 static void sig_handler(int sig __maybe_unused)
 {
        session_done = 1;
@@ -568,6 +566,9 @@ static int __cmd_report(struct perf_report *rep)
                }
        }
 
+       if (session_done())
+               return 0;
+
        if (nr_samples == 0) {
                ui__error("The %s file has no samples!\n", session->filename);
                return 0;
@@ -744,6 +745,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..9c333ff3dfeb3de716eac13d48d7364e998bb50d 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,
@@ -552,8 +553,6 @@ static struct perf_tool perf_script = {
        .ordering_requires_timestamps = true,
 };
 
-extern volatile int session_done;
-
 static void sig_handler(int sig __maybe_unused)
 {
        session_done = 1;
index f686d5ff594e6b93c6e6f732e7a1c97aa18c4e49..5098f144b92defd53e94f9f24184e3ade0672928 100644 (file)
@@ -457,6 +457,7 @@ static int __run_perf_stat(int argc, const char **argv)
                        perror("failed to prepare workload");
                        return -1;
                }
+               child_pid = evsel_list->workload.pid;
        }
 
        if (group)
index b6f0725068bda07d46d43f52c8097003d7375bb7..71aa3e35406bd064e87044d2ae71597a5f117092 100644 (file)
 #include <sys/mman.h>
 #include <linux/futex.h>
 
+/* For older distros: */
+#ifndef MAP_STACK
+# define MAP_STACK             0x20000
+#endif
+
+#ifndef MADV_HWPOISON
+# define MADV_HWPOISON         100
+#endif
+
+#ifndef MADV_MERGEABLE
+# define MADV_MERGEABLE                12
+#endif
+
+#ifndef MADV_UNMERGEABLE
+# define MADV_UNMERGEABLE      13
+#endif
+
 static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
                                         unsigned long arg,
                                         u8 arg_idx __maybe_unused,
@@ -100,7 +117,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 +1013,9 @@ again:
 
                        handler = evsel->handler.func;
                        handler(trace, evsel, &sample);
+
+                       if (done)
+                               goto out_unmap_evlist;
                }
        }
 
@@ -1033,6 +1055,7 @@ static int trace__replay(struct trace *trace)
 
        trace->tool.sample        = trace__process_sample;
        trace->tool.mmap          = perf_event__process_mmap;
+       trace->tool.mmap2         = perf_event__process_mmap2;
        trace->tool.comm          = perf_event__process_comm;
        trace->tool.exit          = perf_event__process_exit;
        trace->tool.fork          = perf_event__process_fork;
index 214e17e97e5c7ba5aa25545b465b8994ac666afc..5f6f9b3271bb0657b77206f6723fd8b3786041bd 100644 (file)
@@ -87,7 +87,7 @@ CFLAGS += -Wall
 CFLAGS += -Wextra
 CFLAGS += -std=gnu99
 
-EXTLIBS = -lelf -lpthread -lrt -lm
+EXTLIBS = -lelf -lpthread -lrt -lm -ldl
 
 ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
   CFLAGS += -fstack-protector-all
@@ -180,6 +180,9 @@ FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
 ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
   CFLAGS += -DLIBELF_MMAP
 endif
+ifeq ($(call try-cc,$(SOURCE_ELF_GETPHDRNUM),$(FLAGS_LIBELF),-DHAVE_ELF_GETPHDRNUM),y)
+  CFLAGS += -DHAVE_ELF_GETPHDRNUM
+endif
 
 # include ARCH specific config
 -include $(src-perf)/arch/$(ARCH)/Makefile
index 708fb8e9822a3ed43bd192470c5da6f01c236c38..f79305739eccdbea8a7ee7dc65be5862543808a4 100644 (file)
@@ -61,6 +61,15 @@ int main(void)
 }
 endef
 
+define SOURCE_ELF_GETPHDRNUM
+#include <libelf.h>
+int main(void)
+{
+       size_t dst;
+       return elf_getphdrnum(0, &dst);
+}
+endef
+
 ifndef NO_SLANG
 define SOURCE_SLANG
 #include <slang.h>
@@ -210,6 +219,7 @@ define SOURCE_LIBAUDIT
 
 int main(void)
 {
+       printf(\"error message: %s\", audit_errno_to_name(0));
        return audit_open();
 }
 endef
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 bfc5a27597d60e1f09b7f95ef691e37608f8c694..7eae5488ecea47344cac10677104cb9e6cb2cc44 100644 (file)
@@ -809,7 +809,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
                    end = map__rip_2objdump(map, sym->end);
 
                offset = line_ip - start;
-               if (offset < 0 || (u64)line_ip > end)
+               if ((u64)line_ip < start || (u64)line_ip > end)
                        offset = -1;
                else
                        parsed_line = tmp2 + 1;
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 3e5f5430a28aa929741e2bd3ccbcf554ae62a074..7defd77105d005f9820c7ca69621e814a3c45c76 100644 (file)
@@ -262,6 +262,21 @@ bool die_is_signed_type(Dwarf_Die *tp_die)
                ret == DW_ATE_signed_fixed);
 }
 
+/**
+ * die_is_func_def - Ensure that this DIE is a subprogram and definition
+ * @dw_die: a DIE
+ *
+ * Ensure that this DIE is a subprogram and NOT a declaration. This
+ * returns true if @dw_die is a function definition.
+ **/
+bool die_is_func_def(Dwarf_Die *dw_die)
+{
+       Dwarf_Attribute attr;
+
+       return (dwarf_tag(dw_die) == DW_TAG_subprogram &&
+               dwarf_attr(dw_die, DW_AT_declaration, &attr) == NULL);
+}
+
 /**
  * die_get_data_member_location - Get the data-member offset
  * @mb_die: a DIE of a member of a data structure
@@ -392,6 +407,10 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
 {
        struct __addr_die_search_param *ad = data;
 
+       /*
+        * Since a declaration entry doesn't has given pc, this always returns
+        * function definition entry.
+        */
        if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
            dwarf_haspc(fn_die, ad->addr)) {
                memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
@@ -407,7 +426,7 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
  * @die_mem: a buffer for result DIE
  *
  * Search a non-inlined function DIE which includes @addr. Stores the
- * DIE to @die_mem and returns it if found. Returns NULl if failed.
+ * DIE to @die_mem and returns it if found. Returns NULL if failed.
  */
 Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
                                    Dwarf_Die *die_mem)
@@ -434,16 +453,33 @@ static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
        return DIE_FIND_CB_CONTINUE;
 }
 
+/**
+ * die_find_top_inlinefunc - Search the top inlined function at given address
+ * @sp_die: a subprogram DIE which including @addr
+ * @addr: target address
+ * @die_mem: a buffer for result DIE
+ *
+ * Search an inlined function DIE which includes @addr. Stores the
+ * DIE to @die_mem and returns it if found. Returns NULL if failed.
+ * Even if several inlined functions are expanded recursively, this
+ * doesn't trace it down, and returns the topmost one.
+ */
+Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
+                                  Dwarf_Die *die_mem)
+{
+       return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
+}
+
 /**
  * die_find_inlinefunc - Search an inlined function at given address
- * @cu_die: a CU DIE which including @addr
+ * @sp_die: a subprogram DIE which including @addr
  * @addr: target address
  * @die_mem: a buffer for result DIE
  *
  * Search an inlined function DIE which includes @addr. Stores the
- * DIE to @die_mem and returns it if found. Returns NULl if failed.
+ * DIE to @die_mem and returns it if found. Returns NULL if failed.
  * If several inlined functions are expanded recursively, this trace
- * it and returns deepest one.
+ * it down and returns deepest one.
  */
 Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
                               Dwarf_Die *die_mem)
index 6ce1717784b7ab42a14d58431c3026df749f0620..b4fe90c6cb2d4413c3ab96f91a346f3f89549932 100644 (file)
@@ -38,6 +38,9 @@ extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
 extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
                        int (*callback)(Dwarf_Die *, void *), void *data);
 
+/* Ensure that this DIE is a subprogram and definition (not declaration) */
+extern bool die_is_func_def(Dwarf_Die *dw_die);
+
 /* Compare diename and tname */
 extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
 
@@ -76,7 +79,11 @@ extern Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
 extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
                                    Dwarf_Die *die_mem);
 
-/* Search an inlined function including given address */
+/* Search the top inlined function including given address */
+extern Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
+                                         Dwarf_Die *die_mem);
+
+/* Search the deepest inlined function including given address */
 extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
                                      Dwarf_Die *die_mem);
 
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..c3e5a3b817ab714497dc7f6f39520945dc886b1a 100644 (file)
@@ -199,9 +199,11 @@ static int write_buildid(char *name, size_t name_len, u8 *build_id,
        return write_padded(fd, name, name_len + 1, len);
 }
 
-static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
-                               u16 misc, int fd)
+static int __dsos__write_buildid_table(struct list_head *head,
+                                      struct machine *machine,
+                                      pid_t pid, u16 misc, int fd)
 {
+       char nm[PATH_MAX];
        struct dso *pos;
 
        dsos__for_each_with_build_id(pos, head) {
@@ -215,6 +217,10 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
                if (is_vdso_map(pos->short_name)) {
                        name = (char *) VDSO__MAP_NAME;
                        name_len = sizeof(VDSO__MAP_NAME) + 1;
+               } else if (dso__is_kcore(pos)) {
+                       machine__mmap_name(machine, nm, sizeof(nm));
+                       name = nm;
+                       name_len = strlen(nm) + 1;
                } else {
                        name = pos->long_name;
                        name_len = pos->long_name_len + 1;
@@ -240,10 +246,10 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
                umisc = PERF_RECORD_MISC_GUEST_USER;
        }
 
-       err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid,
-                                         kmisc, fd);
+       err = __dsos__write_buildid_table(&machine->kernel_dsos, machine,
+                                         machine->pid, kmisc, fd);
        if (err == 0)
-               err = __dsos__write_buildid_table(&machine->user_dsos,
+               err = __dsos__write_buildid_table(&machine->user_dsos, machine,
                                                  machine->pid, umisc, fd);
        return err;
 }
@@ -375,23 +381,31 @@ out_free:
        return err;
 }
 
-static int dso__cache_build_id(struct dso *dso, const char *debugdir)
+static int dso__cache_build_id(struct dso *dso, struct machine *machine,
+                              const char *debugdir)
 {
        bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
        bool is_vdso = is_vdso_map(dso->short_name);
+       char *name = dso->long_name;
+       char nm[PATH_MAX];
 
-       return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id),
-                                    dso->long_name, debugdir,
-                                    is_kallsyms, is_vdso);
+       if (dso__is_kcore(dso)) {
+               is_kallsyms = true;
+               machine__mmap_name(machine, nm, sizeof(nm));
+               name = nm;
+       }
+       return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
+                                    debugdir, is_kallsyms, is_vdso);
 }
 
-static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
+static int __dsos__cache_build_ids(struct list_head *head,
+                                  struct machine *machine, const char *debugdir)
 {
        struct dso *pos;
        int err = 0;
 
        dsos__for_each_with_build_id(pos, head)
-               if (dso__cache_build_id(pos, debugdir))
+               if (dso__cache_build_id(pos, machine, debugdir))
                        err = -1;
 
        return err;
@@ -399,8 +413,9 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
 
 static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
 {
-       int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir);
-       ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir);
+       int ret = __dsos__cache_build_ids(&machine->kernel_dsos, machine,
+                                         debugdir);
+       ret |= __dsos__cache_build_ids(&machine->user_dsos, machine, debugdir);
        return ret;
 }
 
@@ -1351,6 +1366,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++) {
@@ -2750,6 +2768,18 @@ int perf_session__read_header(struct perf_session *session)
        if (perf_file_header__read(&f_header, header, fd) < 0)
                return -EINVAL;
 
+       /*
+        * Sanity check that perf.data was written cleanly; data size is
+        * initialized to 0 and updated only if the on_exit function is run.
+        * If data size is still 0 then the file contains only partial
+        * information.  Just warn user and process it as much as it can.
+        */
+       if (f_header.data.size == 0) {
+               pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n"
+                          "Was the 'perf record' command properly terminated?\n",
+                          session->filename);
+       }
+
        nr_attrs = f_header.attrs.size / f_header.attr_size;
        lseek(fd, f_header.attrs.offset, SEEK_SET);
 
index 46a0d35a05e1f21aae097e7a67cea89bfe9ecddf..9ff6cf3e9a99f69596b37372f60203c11bec88a3 100644 (file)
@@ -611,6 +611,8 @@ void hists__collapse_resort(struct hists *hists)
        next = rb_first(root);
 
        while (next) {
+               if (session_done())
+                       break;
                n = rb_entry(next, struct hist_entry, rb_node_in);
                next = rb_next(&n->rb_node_in);
 
index 1dca61f0512d672abb257cf093cf4539835c30eb..6188d2876a7128aaa68e426c3334dfcae099dc41 100644 (file)
@@ -792,7 +792,7 @@ static int machine__create_modules(struct machine *machine)
                modules = path;
        }
 
-       if (symbol__restricted_filename(path, "/proc/modules"))
+       if (symbol__restricted_filename(modules, "/proc/modules"))
                return -1;
 
        file = fopen(modules, "r");
@@ -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 be0329394d5639f77644d8a9079dd6ceb4f27a73..c09e0a9fdf4cda118be077fbee1fb382dcc3d5ee 100644 (file)
@@ -118,7 +118,6 @@ static const Dwfl_Callbacks offline_callbacks = {
 static int debuginfo__init_offline_dwarf(struct debuginfo *self,
                                         const char *path)
 {
-       Dwfl_Module *mod;
        int fd;
 
        fd = open(path, O_RDONLY);
@@ -129,11 +128,11 @@ static int debuginfo__init_offline_dwarf(struct debuginfo *self,
        if (!self->dwfl)
                goto error;
 
-       mod = dwfl_report_offline(self->dwfl, "", "", fd);
-       if (!mod)
+       self->mod = dwfl_report_offline(self->dwfl, "", "", fd);
+       if (!self->mod)
                goto error;
 
-       self->dbg = dwfl_module_getdwarf(mod, &self->bias);
+       self->dbg = dwfl_module_getdwarf(self->mod, &self->bias);
        if (!self->dbg)
                goto error;
 
@@ -676,37 +675,42 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
 }
 
 /* Convert subprogram DIE to trace point */
-static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
-                                 bool retprobe, struct probe_trace_point *tp)
+static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
+                                 Dwarf_Addr paddr, bool retprobe,
+                                 struct probe_trace_point *tp)
 {
        Dwarf_Addr eaddr, highaddr;
-       const char *name;
-
-       /* Copy the name of probe point */
-       name = dwarf_diename(sp_die);
-       if (name) {
-               if (dwarf_entrypc(sp_die, &eaddr) != 0) {
-                       pr_warning("Failed to get entry address of %s\n",
-                                  dwarf_diename(sp_die));
-                       return -ENOENT;
-               }
-               if (dwarf_highpc(sp_die, &highaddr) != 0) {
-                       pr_warning("Failed to get end address of %s\n",
-                                  dwarf_diename(sp_die));
-                       return -ENOENT;
-               }
-               if (paddr > highaddr) {
-                       pr_warning("Offset specified is greater than size of %s\n",
-                                  dwarf_diename(sp_die));
-                       return -EINVAL;
-               }
-               tp->symbol = strdup(name);
-               if (tp->symbol == NULL)
-                       return -ENOMEM;
-               tp->offset = (unsigned long)(paddr - eaddr);
-       } else
-               /* This function has no name. */
-               tp->offset = (unsigned long)paddr;
+       GElf_Sym sym;
+       const char *symbol;
+
+       /* Verify the address is correct */
+       if (dwarf_entrypc(sp_die, &eaddr) != 0) {
+               pr_warning("Failed to get entry address of %s\n",
+                          dwarf_diename(sp_die));
+               return -ENOENT;
+       }
+       if (dwarf_highpc(sp_die, &highaddr) != 0) {
+               pr_warning("Failed to get end address of %s\n",
+                          dwarf_diename(sp_die));
+               return -ENOENT;
+       }
+       if (paddr > highaddr) {
+               pr_warning("Offset specified is greater than size of %s\n",
+                          dwarf_diename(sp_die));
+               return -EINVAL;
+       }
+
+       /* Get an appropriate symbol from symtab */
+       symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
+       if (!symbol) {
+               pr_warning("Failed to find symbol at 0x%lx\n",
+                          (unsigned long)paddr);
+               return -ENOENT;
+       }
+       tp->offset = (unsigned long)(paddr - sym.st_value);
+       tp->symbol = strdup(symbol);
+       if (!tp->symbol)
+               return -ENOMEM;
 
        /* Return probe must be on the head of a subprogram */
        if (retprobe) {
@@ -734,7 +738,7 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
        }
 
        /* If not a real subprogram, find a real one */
-       if (dwarf_tag(sc_die) != DW_TAG_subprogram) {
+       if (!die_is_func_def(sc_die)) {
                if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
                        pr_warning("Failed to find probe point in any "
                                   "functions.\n");
@@ -980,12 +984,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
        struct dwarf_callback_param *param = data;
        struct probe_finder *pf = param->data;
        struct perf_probe_point *pp = &pf->pev->point;
-       Dwarf_Attribute attr;
 
        /* Check tag and diename */
-       if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
-           !die_compare_name(sp_die, pp->function) ||
-           dwarf_attr(sp_die, DW_AT_declaration, &attr))
+       if (!die_is_func_def(sp_die) ||
+           !die_compare_name(sp_die, pp->function))
                return DWARF_CB_OK;
 
        /* Check declared file */
@@ -1151,7 +1153,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
        tev = &tf->tevs[tf->ntevs++];
 
        /* Trace point should be converted from subprogram DIE */
-       ret = convert_to_trace_point(&pf->sp_die, pf->addr,
+       ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
                                     pf->pev->point.retprobe, &tev->point);
        if (ret < 0)
                return ret;
@@ -1183,7 +1185,7 @@ int debuginfo__find_trace_events(struct debuginfo *self,
 {
        struct trace_event_finder tf = {
                        .pf = {.pev = pev, .callback = add_probe_trace_event},
-                       .max_tevs = max_tevs};
+                       .mod = self->mod, .max_tevs = max_tevs};
        int ret;
 
        /* Allocate result tevs array */
@@ -1252,7 +1254,7 @@ static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
        vl = &af->vls[af->nvls++];
 
        /* Trace point should be converted from subprogram DIE */
-       ret = convert_to_trace_point(&pf->sp_die, pf->addr,
+       ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr,
                                     pf->pev->point.retprobe, &vl->point);
        if (ret < 0)
                return ret;
@@ -1291,6 +1293,7 @@ int debuginfo__find_available_vars_at(struct debuginfo *self,
 {
        struct available_var_finder af = {
                        .pf = {.pev = pev, .callback = add_available_vars},
+                       .mod = self->mod,
                        .max_vls = max_vls, .externs = externs};
        int ret;
 
@@ -1324,8 +1327,8 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
                                struct perf_probe_point *ppt)
 {
        Dwarf_Die cudie, spdie, indie;
-       Dwarf_Addr _addr, baseaddr;
-       const char *fname = NULL, *func = NULL, *tmp;
+       Dwarf_Addr _addr = 0, baseaddr = 0;
+       const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp;
        int baseline = 0, lineno = 0, ret = 0;
 
        /* Adjust address with bias */
@@ -1346,27 +1349,36 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
        /* Find a corresponding function (name, baseline and baseaddr) */
        if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) {
                /* Get function entry information */
-               tmp = dwarf_diename(&spdie);
-               if (!tmp ||
+               func = basefunc = dwarf_diename(&spdie);
+               if (!func ||
                    dwarf_entrypc(&spdie, &baseaddr) != 0 ||
-                   dwarf_decl_line(&spdie, &baseline) != 0)
+                   dwarf_decl_line(&spdie, &baseline) != 0) {
+                       lineno = 0;
                        goto post;
-               func = tmp;
+               }
 
-               if (addr == (unsigned long)baseaddr)
+               if (addr == (unsigned long)baseaddr) {
                        /* Function entry - Relative line number is 0 */
                        lineno = baseline;
-               else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
-                                            &indie)) {
+                       fname = dwarf_decl_file(&spdie);
+                       goto post;
+               }
+
+               /* Track down the inline functions step by step */
+               while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr,
+                                               &indie)) {
+                       /* There is an inline function */
                        if (dwarf_entrypc(&indie, &_addr) == 0 &&
-                           _addr == addr)
+                           _addr == addr) {
                                /*
                                 * addr is at an inline function entry.
                                 * In this case, lineno should be the call-site
-                                * line number.
+                                * line number. (overwrite lineinfo)
                                 */
                                lineno = die_get_call_lineno(&indie);
-                       else {
+                               fname = die_get_call_file(&indie);
+                               break;
+                       } else {
                                /*
                                 * addr is in an inline function body.
                                 * Since lineno points one of the lines
@@ -1374,19 +1386,27 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
                                 * be the entry line of the inline function.
                                 */
                                tmp = dwarf_diename(&indie);
-                               if (tmp &&
-                                   dwarf_decl_line(&spdie, &baseline) == 0)
-                                       func = tmp;
+                               if (!tmp ||
+                                   dwarf_decl_line(&indie, &baseline) != 0)
+                                       break;
+                               func = tmp;
+                               spdie = indie;
                        }
                }
+               /* Verify the lineno and baseline are in a same file */
+               tmp = dwarf_decl_file(&spdie);
+               if (!tmp || strcmp(tmp, fname) != 0)
+                       lineno = 0;
        }
 
 post:
        /* Make a relative line number or an offset */
        if (lineno)
                ppt->line = lineno - baseline;
-       else if (func)
+       else if (basefunc) {
                ppt->offset = addr - (unsigned long)baseaddr;
+               func = basefunc;
+       }
 
        /* Duplicate strings */
        if (func) {
@@ -1474,7 +1494,7 @@ static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
        return 0;
 }
 
-/* Search function from function name */
+/* Search function definition from function name */
 static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
 {
        struct dwarf_callback_param *param = data;
@@ -1485,7 +1505,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
        if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die)))
                return DWARF_CB_OK;
 
-       if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
+       if (die_is_func_def(sp_die) &&
            die_compare_name(sp_die, lr->function)) {
                lf->fname = dwarf_decl_file(sp_die);
                dwarf_decl_line(sp_die, &lr->offset);
index 17e94d0c36f981dbf8dbc245410b9a4aa511d16c..3b7d63018960d7ff6a6808ce81eff2d34b40bd09 100644 (file)
@@ -23,6 +23,7 @@ static inline int is_c_varname(const char *name)
 /* debug information structure */
 struct debuginfo {
        Dwarf           *dbg;
+       Dwfl_Module     *mod;
        Dwfl            *dwfl;
        Dwarf_Addr      bias;
 };
@@ -77,6 +78,7 @@ struct probe_finder {
 
 struct trace_event_finder {
        struct probe_finder     pf;
+       Dwfl_Module             *mod;           /* For solving symbols */
        struct probe_trace_event *tevs;         /* Found trace events */
        int                     ntevs;          /* Number of trace events */
        int                     max_tevs;       /* Max number of trace events */
@@ -84,6 +86,7 @@ struct trace_event_finder {
 
 struct available_var_finder {
        struct probe_finder     pf;
+       Dwfl_Module             *mod;           /* For solving symbols */
        struct variable_list    *vls;           /* Found variable lists */
        int                     nvls;           /* Number of variable lists */
        int                     max_vls;        /* Max no. of variable lists */
index 1fc0c628683eea5b90d4e14f7efb7026d40cf0a2..568b750c01f60b3d81cda29966ed40534a7bc8e1 100644 (file)
@@ -256,6 +256,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
                tool->sample = process_event_sample_stub;
        if (tool->mmap == NULL)
                tool->mmap = process_event_stub;
+       if (tool->mmap2 == NULL)
+               tool->mmap2 = process_event_stub;
        if (tool->comm == NULL)
                tool->comm = process_event_stub;
        if (tool->fork == NULL)
@@ -351,6 +353,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 +476,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,12 +526,16 @@ 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)
                return 0;
 
        list_for_each_entry_safe(iter, tmp, head, list) {
+               if (session_done())
+                       return 0;
+
                if (iter->timestamp > limit)
                        break;
 
@@ -526,7 +552,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 +876,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 +1004,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:
@@ -1136,7 +1165,6 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
        }
 }
 
-#define session_done() (*(volatile int *)(&session_done))
 volatile int session_done;
 
 static int __perf_session__process_pipe_events(struct perf_session *self,
@@ -1284,7 +1312,7 @@ int __perf_session__process_events(struct perf_session *session,
        file_offset = page_offset;
        head = data_offset - page_offset;
 
-       if (data_offset + data_size < file_size)
+       if (data_size && (data_offset + data_size < file_size))
                file_size = data_offset + data_size;
 
        progress_next = file_size / 16;
@@ -1348,10 +1376,13 @@ more:
                                    "Processing events...");
        }
 
+       err = 0;
+       if (session_done())
+               goto out_err;
+
        if (file_pos < file_size)
                goto more;
 
-       err = 0;
        /* do the final flush for ordered samples */
        session->ordered_samples.next_flush = ULLONG_MAX;
        err = flush_sample_queue(session, tool);
@@ -1619,52 +1650,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 3aa75fb2225f7129daa12f7e86219f30928e5e42..04bf7373a7e5fb04222b1a9cdb5c295045c0626f 100644 (file)
@@ -124,4 +124,8 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
 
 #define perf_session__set_tracepoints_handlers(session, array) \
        __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array))
+
+extern volatile int session_done;
+
+#define session_done() (*(volatile int *)(&session_done))
 #endif /* __PERF_SESSION_H */
index a7b9ab55738086c24d12d7e9ee8cb6143ffd47aa..a9c829be52169eac5b9f00d9382fd9281152b9e6 100644 (file)
@@ -8,6 +8,22 @@
 #include "symbol.h"
 #include "debug.h"
 
+#ifndef HAVE_ELF_GETPHDRNUM
+static int elf_getphdrnum(Elf *elf, size_t *dst)
+{
+       GElf_Ehdr gehdr;
+       GElf_Ehdr *ehdr;
+
+       ehdr = gelf_getehdr(elf, &gehdr);
+       if (!ehdr)
+               return -1;
+
+       *dst = ehdr->e_phnum;
+
+       return 0;
+}
+#endif
+
 #ifndef NT_GNU_BUILD_ID
 #define NT_GNU_BUILD_ID 3
 #endif
index 62b16b6165bafae5fd80cb79d1670628f1d81847..4385816d3d49643c981f64a310eaaef6d9838738 100644 (file)
@@ -29,6 +29,7 @@ struct perf_tool {
        event_sample    sample,
                        read;
        event_op        mmap,
+                       mmap2,
                        comm,
                        fork,
                        exit,
index fe7a27d67d2b7af23a596683509769a4f1bd6e38..e9e1c03f927d27bce1e041a9cc61ca47dae2b987 100644 (file)
@@ -186,7 +186,7 @@ void parse_proc_kallsyms(struct pevent *pevent,
        char *next = NULL;
        char *addr_str;
        char *mod;
-       char *fmt;
+       char *fmt = NULL;
 
        line = strtok_r(file, "\n", &next);
        while (line) {
index 4fa655d68a81c8a1b8dd8b60f885721edc7cfea1..41bd85559d4b01aa8ee0e89615ece47c4115b0d0 100644 (file)
@@ -151,7 +151,7 @@ static int check_timer_create(int which)
        fflush(stdout);
 
        done = 0;
-       timer_create(which, NULL, &id);
+       err = timer_create(which, NULL, &id);
        if (err < 0) {
                perror("Can't create timer\n");
                return -1;
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..a9dd682cf5e3f5117de017156396337a8352914f 100644 (file)
@@ -1058,12 +1058,18 @@ 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)
 {
-       return __gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL, false);
+       struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
+       unsigned long hva = __gfn_to_hva_many(slot, gfn, NULL, false);
+
+       if (!kvm_is_error_hva(hva) && writable)
+               *writable = !memslot_is_readonly(slot);
+
+       return hva;
 }
 
 static int kvm_read_hva(void *data, void __user *hva, int len)
@@ -1430,7 +1436,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 +1474,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();